blob: ac37f73fe08d71f94990375c4760aa398ccae805 [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 *
15 * 14 Nov 2000 ht - truncated declaration of xmlXPathEvalRelativeLocationPath
16 * for VMS
17 */
18
Daniel Veillard34ce8be2002-03-18 19:37:11 +000019#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000020#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000021#ifdef LIBXML_XPATH_ENABLED
22
Owen Taylor3473f882001-02-23 17:55:21 +000023#include <string.h>
24
25#ifdef HAVE_SYS_TYPES_H
26#include <sys/types.h>
27#endif
28#ifdef HAVE_MATH_H
29#include <math.h>
30#endif
31#ifdef HAVE_FLOAT_H
32#include <float.h>
33#endif
Owen Taylor3473f882001-02-23 17:55:21 +000034#ifdef HAVE_CTYPE_H
35#include <ctype.h>
36#endif
Daniel Veillard5792e162001-04-30 17:44:45 +000037#ifdef HAVE_SIGNAL_H
Daniel Veillardb45c43b2001-04-28 17:02:11 +000038#include <signal.h>
Daniel Veillardb45c43b2001-04-28 17:02:11 +000039#endif
Owen Taylor3473f882001-02-23 17:55:21 +000040
41#include <libxml/xmlmemory.h>
42#include <libxml/tree.h>
43#include <libxml/valid.h>
44#include <libxml/xpath.h>
45#include <libxml/xpathInternals.h>
46#include <libxml/parserInternals.h>
47#include <libxml/hash.h>
48#ifdef LIBXML_XPTR_ENABLED
49#include <libxml/xpointer.h>
50#endif
51#ifdef LIBXML_DEBUG_ENABLED
52#include <libxml/debugXML.h>
53#endif
54#include <libxml/xmlerror.h>
Daniel Veillard81463942001-10-16 12:34:39 +000055#include <libxml/threads.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000056#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000057
58/* #define DEBUG */
59/* #define DEBUG_STEP */
Daniel Veillardf06307e2001-07-03 10:35:50 +000060/* #define DEBUG_STEP_NTH */
Owen Taylor3473f882001-02-23 17:55:21 +000061/* #define DEBUG_EXPR */
Daniel Veillardf06307e2001-07-03 10:35:50 +000062/* #define DEBUG_EVAL_COUNTS */
Owen Taylor3473f882001-02-23 17:55:21 +000063
Daniel Veillard5792e162001-04-30 17:44:45 +000064double xmlXPathDivideBy(double f, double fzero);
Owen Taylor3473f882001-02-23 17:55:21 +000065
Daniel Veillard20ee8c02001-10-05 09:18:14 +000066static xmlNs xmlXPathXMLNamespaceStruct = {
67 NULL,
68 XML_NAMESPACE_DECL,
69 XML_XML_NAMESPACE,
70 BAD_CAST "xml"
71};
72static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
Daniel Veillard81463942001-10-16 12:34:39 +000073#ifndef LIBXML_THREADS_ENABLED
74/*
75 * Optimizer is disabled only when threaded apps are detected while
76 * the library ain't compiled for thread safety.
77 */
78static int xmlXPathDisableOptimizer = 0;
79#endif
Daniel Veillard20ee8c02001-10-05 09:18:14 +000080
Daniel Veillard9e7160d2001-03-18 23:17:47 +000081/************************************************************************
82 * *
83 * Floating point stuff *
84 * *
85 ************************************************************************/
86
Daniel Veillardc0631a62001-09-20 13:56:06 +000087#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +000088#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +000089#endif
Daniel Veillardcda96922001-08-21 10:56:31 +000090#include "trionan.c"
91
Owen Taylor3473f882001-02-23 17:55:21 +000092/*
Owen Taylor3473f882001-02-23 17:55:21 +000093 * The lack of portability of this section of the libc is annoying !
94 */
95double xmlXPathNAN = 0;
96double xmlXPathPINF = 1;
97double xmlXPathNINF = -1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +000098double xmlXPathNZERO = 0;
Daniel Veillard20ee8c02001-10-05 09:18:14 +000099static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000100
Owen Taylor3473f882001-02-23 17:55:21 +0000101/**
102 * xmlXPathInit:
103 *
104 * Initialize the XPath environment
105 */
106void
107xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000108 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +0000109
Bjorn Reese45029602001-08-21 09:23:53 +0000110 xmlXPathPINF = trio_pinf();
111 xmlXPathNINF = trio_ninf();
112 xmlXPathNAN = trio_nan();
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000113 xmlXPathNZERO = trio_nzero();
Owen Taylor3473f882001-02-23 17:55:21 +0000114
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000115 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000116}
117
Daniel Veillardcda96922001-08-21 10:56:31 +0000118/**
119 * xmlXPathIsNaN:
120 * @val: a double value
121 *
122 * Provides a portable isnan() function to detect whether a double
123 * is a NotaNumber. Based on trio code
124 * http://sourceforge.net/projects/ctrio/
125 *
126 * Returns 1 if the value is a NaN, 0 otherwise
127 */
128int
129xmlXPathIsNaN(double val) {
130 return(trio_isnan(val));
131}
132
133/**
134 * xmlXPathIsInf:
135 * @val: a double value
136 *
137 * Provides a portable isinf() function to detect whether a double
138 * is a +Infinite or -Infinite. Based on trio code
139 * http://sourceforge.net/projects/ctrio/
140 *
141 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
142 */
143int
144xmlXPathIsInf(double val) {
145 return(trio_isinf(val));
146}
147
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000148/**
149 * xmlXPathGetSign:
150 * @val: a double value
151 *
152 * Provides a portable function to detect the sign of a double
153 * Modified from trio code
154 * http://sourceforge.net/projects/ctrio/
155 *
156 * Returns 1 if the value is Negative, 0 if positive
157 */
Daniel Veillard21458c82002-03-27 16:12:22 +0000158static int
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000159xmlXPathGetSign(double val) {
Daniel Veillard21458c82002-03-27 16:12:22 +0000160 return(trio_signbit(val));
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000161}
162
163
Owen Taylor3473f882001-02-23 17:55:21 +0000164/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000165 * *
166 * Parser Types *
167 * *
168 ************************************************************************/
169
170/*
171 * Types are private:
172 */
173
174typedef enum {
175 XPATH_OP_END=0,
176 XPATH_OP_AND,
177 XPATH_OP_OR,
178 XPATH_OP_EQUAL,
179 XPATH_OP_CMP,
180 XPATH_OP_PLUS,
181 XPATH_OP_MULT,
182 XPATH_OP_UNION,
183 XPATH_OP_ROOT,
184 XPATH_OP_NODE,
185 XPATH_OP_RESET,
186 XPATH_OP_COLLECT,
187 XPATH_OP_VALUE,
188 XPATH_OP_VARIABLE,
189 XPATH_OP_FUNCTION,
190 XPATH_OP_ARG,
191 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000192 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000193 XPATH_OP_SORT
194#ifdef LIBXML_XPTR_ENABLED
195 ,XPATH_OP_RANGETO
196#endif
197} xmlXPathOp;
198
199typedef enum {
200 AXIS_ANCESTOR = 1,
201 AXIS_ANCESTOR_OR_SELF,
202 AXIS_ATTRIBUTE,
203 AXIS_CHILD,
204 AXIS_DESCENDANT,
205 AXIS_DESCENDANT_OR_SELF,
206 AXIS_FOLLOWING,
207 AXIS_FOLLOWING_SIBLING,
208 AXIS_NAMESPACE,
209 AXIS_PARENT,
210 AXIS_PRECEDING,
211 AXIS_PRECEDING_SIBLING,
212 AXIS_SELF
213} xmlXPathAxisVal;
214
215typedef enum {
216 NODE_TEST_NONE = 0,
217 NODE_TEST_TYPE = 1,
218 NODE_TEST_PI = 2,
219 NODE_TEST_ALL = 3,
220 NODE_TEST_NS = 4,
221 NODE_TEST_NAME = 5
222} xmlXPathTestVal;
223
224typedef enum {
225 NODE_TYPE_NODE = 0,
226 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
227 NODE_TYPE_TEXT = XML_TEXT_NODE,
228 NODE_TYPE_PI = XML_PI_NODE
229} xmlXPathTypeVal;
230
231
232typedef struct _xmlXPathStepOp xmlXPathStepOp;
233typedef xmlXPathStepOp *xmlXPathStepOpPtr;
234struct _xmlXPathStepOp {
235 xmlXPathOp op;
236 int ch1;
237 int ch2;
238 int value;
239 int value2;
240 int value3;
241 void *value4;
242 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000243 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000244 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000245};
246
247struct _xmlXPathCompExpr {
248 int nbStep;
249 int maxStep;
250 xmlXPathStepOp *steps; /* ops for computation */
251 int last;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000252#ifdef DEBUG_EVAL_COUNTS
253 int nb;
254 xmlChar *string;
255#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000256};
257
258/************************************************************************
259 * *
260 * Parser Type functions *
261 * *
262 ************************************************************************/
263
264/**
265 * xmlXPathNewCompExpr:
266 *
267 * Create a new Xpath component
268 *
269 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
270 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000271static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000272xmlXPathNewCompExpr(void) {
273 xmlXPathCompExprPtr cur;
274
275 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
276 if (cur == NULL) {
277 xmlGenericError(xmlGenericErrorContext,
278 "xmlXPathNewCompExpr : malloc failed\n");
279 return(NULL);
280 }
281 memset(cur, 0, sizeof(xmlXPathCompExpr));
282 cur->maxStep = 10;
283 cur->nbStep = 0;
284 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
285 sizeof(xmlXPathStepOp));
286 if (cur->steps == NULL) {
287 xmlGenericError(xmlGenericErrorContext,
288 "xmlXPathNewCompExpr : malloc failed\n");
289 xmlFree(cur);
290 return(NULL);
291 }
292 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
293 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000294#ifdef DEBUG_EVAL_COUNTS
295 cur->nb = 0;
296#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000297 return(cur);
298}
299
300/**
301 * xmlXPathFreeCompExpr:
302 * @comp: an XPATH comp
303 *
304 * Free up the memory allocated by @comp
305 */
306void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000307xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
308{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000309 xmlXPathStepOpPtr op;
310 int i;
311
312 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000313 return;
314 for (i = 0; i < comp->nbStep; i++) {
315 op = &comp->steps[i];
316 if (op->value4 != NULL) {
317 if (op->op == XPATH_OP_VALUE)
318 xmlXPathFreeObject(op->value4);
319 else
320 xmlFree(op->value4);
321 }
322 if (op->value5 != NULL)
323 xmlFree(op->value5);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000324 }
325 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000326 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000327 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000328#ifdef DEBUG_EVAL_COUNTS
329 if (comp->string != NULL) {
330 xmlFree(comp->string);
331 }
332#endif
333
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000334 xmlFree(comp);
335}
336
337/**
338 * xmlXPathCompExprAdd:
339 * @comp: the compiled expression
340 * @ch1: first child index
341 * @ch2: second child index
342 * @op: an op
343 * @value: the first int value
344 * @value2: the second int value
345 * @value3: the third int value
346 * @value4: the first string value
347 * @value5: the second string value
348 *
349 * Add an step to an XPath Compiled Expression
350 *
351 * Returns -1 in case of failure, the index otherwise
352 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000353static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000354xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
355 xmlXPathOp op, int value,
356 int value2, int value3, void *value4, void *value5) {
357 if (comp->nbStep >= comp->maxStep) {
358 xmlXPathStepOp *real;
359
360 comp->maxStep *= 2;
361 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
362 comp->maxStep * sizeof(xmlXPathStepOp));
363 if (real == NULL) {
364 comp->maxStep /= 2;
365 xmlGenericError(xmlGenericErrorContext,
366 "xmlXPathCompExprAdd : realloc failed\n");
367 return(-1);
368 }
369 comp->steps = real;
370 }
371 comp->last = comp->nbStep;
372 comp->steps[comp->nbStep].ch1 = ch1;
373 comp->steps[comp->nbStep].ch2 = ch2;
374 comp->steps[comp->nbStep].op = op;
375 comp->steps[comp->nbStep].value = value;
376 comp->steps[comp->nbStep].value2 = value2;
377 comp->steps[comp->nbStep].value3 = value3;
378 comp->steps[comp->nbStep].value4 = value4;
379 comp->steps[comp->nbStep].value5 = value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000380 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000381 return(comp->nbStep++);
382}
383
Daniel Veillardf06307e2001-07-03 10:35:50 +0000384/**
385 * xmlXPathCompSwap:
386 * @comp: the compiled expression
387 * @op: operation index
388 *
389 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000390 */
391static void
392xmlXPathCompSwap(xmlXPathStepOpPtr op) {
393 int tmp;
394
Daniel Veillard81463942001-10-16 12:34:39 +0000395#ifdef LIBXML_THREADS_ENABLED
396 /*
397 * Since this manipulates possibly shared variables, this is
398 * disable if one detects that the library is used in a multithreaded
399 * application
400 */
401 if (xmlXPathDisableOptimizer)
402 return;
403#endif
404
Daniel Veillardf06307e2001-07-03 10:35:50 +0000405 tmp = op->ch1;
406 op->ch1 = op->ch2;
407 op->ch2 = tmp;
408}
409
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000410#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
411 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
412 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000413#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
414 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
415 (op), (val), (val2), (val3), (val4), (val5))
416
417#define PUSH_LEAVE_EXPR(op, val, val2) \
418xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
419
420#define PUSH_UNARY_EXPR(op, ch, val, val2) \
421xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
422
423#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
424xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), (val), (val2), 0 ,NULL ,NULL)
425
426/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000427 * *
428 * Debugging related functions *
429 * *
430 ************************************************************************/
431
432#define TODO \
433 xmlGenericError(xmlGenericErrorContext, \
434 "Unimplemented block at %s:%d\n", \
435 __FILE__, __LINE__);
436
437#define STRANGE \
438 xmlGenericError(xmlGenericErrorContext, \
439 "Internal error at %s:%d\n", \
440 __FILE__, __LINE__);
441
442#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000443static void
444xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000445 int i;
446 char shift[100];
447
448 for (i = 0;((i < depth) && (i < 25));i++)
449 shift[2 * i] = shift[2 * i + 1] = ' ';
450 shift[2 * i] = shift[2 * i + 1] = 0;
451 if (cur == NULL) {
452 fprintf(output, shift);
453 fprintf(output, "Node is NULL !\n");
454 return;
455
456 }
457
458 if ((cur->type == XML_DOCUMENT_NODE) ||
459 (cur->type == XML_HTML_DOCUMENT_NODE)) {
460 fprintf(output, shift);
461 fprintf(output, " /\n");
462 } else if (cur->type == XML_ATTRIBUTE_NODE)
463 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
464 else
465 xmlDebugDumpOneNode(output, cur, depth);
466}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000467static void
468xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000469 xmlNodePtr tmp;
470 int i;
471 char shift[100];
472
473 for (i = 0;((i < depth) && (i < 25));i++)
474 shift[2 * i] = shift[2 * i + 1] = ' ';
475 shift[2 * i] = shift[2 * i + 1] = 0;
476 if (cur == NULL) {
477 fprintf(output, shift);
478 fprintf(output, "Node is NULL !\n");
479 return;
480
481 }
482
483 while (cur != NULL) {
484 tmp = cur;
485 cur = cur->next;
486 xmlDebugDumpOneNode(output, tmp, depth);
487 }
488}
Owen Taylor3473f882001-02-23 17:55:21 +0000489
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000490static void
491xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000492 int i;
493 char shift[100];
494
495 for (i = 0;((i < depth) && (i < 25));i++)
496 shift[2 * i] = shift[2 * i + 1] = ' ';
497 shift[2 * i] = shift[2 * i + 1] = 0;
498
499 if (cur == NULL) {
500 fprintf(output, shift);
501 fprintf(output, "NodeSet is NULL !\n");
502 return;
503
504 }
505
Daniel Veillard911f49a2001-04-07 15:39:35 +0000506 if (cur != NULL) {
507 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
508 for (i = 0;i < cur->nodeNr;i++) {
509 fprintf(output, shift);
510 fprintf(output, "%d", i + 1);
511 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
512 }
Owen Taylor3473f882001-02-23 17:55:21 +0000513 }
514}
515
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000516static void
517xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000518 int i;
519 char shift[100];
520
521 for (i = 0;((i < depth) && (i < 25));i++)
522 shift[2 * i] = shift[2 * i + 1] = ' ';
523 shift[2 * i] = shift[2 * i + 1] = 0;
524
525 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
526 fprintf(output, shift);
527 fprintf(output, "Value Tree is NULL !\n");
528 return;
529
530 }
531
532 fprintf(output, shift);
533 fprintf(output, "%d", i + 1);
534 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
535}
Owen Taylor3473f882001-02-23 17:55:21 +0000536#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000537static void
538xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000539 int i;
540 char shift[100];
541
542 for (i = 0;((i < depth) && (i < 25));i++)
543 shift[2 * i] = shift[2 * i + 1] = ' ';
544 shift[2 * i] = shift[2 * i + 1] = 0;
545
546 if (cur == NULL) {
547 fprintf(output, shift);
548 fprintf(output, "LocationSet is NULL !\n");
549 return;
550
551 }
552
553 for (i = 0;i < cur->locNr;i++) {
554 fprintf(output, shift);
555 fprintf(output, "%d : ", i + 1);
556 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
557 }
558}
Daniel Veillard017b1082001-06-21 11:20:21 +0000559#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000560
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000561/**
562 * xmlXPathDebugDumpObject:
563 * @output: the FILE * to dump the output
564 * @cur: the object to inspect
565 * @depth: indentation level
566 *
567 * Dump the content of the object for debugging purposes
568 */
569void
570xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000571 int i;
572 char shift[100];
573
574 for (i = 0;((i < depth) && (i < 25));i++)
575 shift[2 * i] = shift[2 * i + 1] = ' ';
576 shift[2 * i] = shift[2 * i + 1] = 0;
577
578 fprintf(output, shift);
579
580 if (cur == NULL) {
581 fprintf(output, "Object is empty (NULL)\n");
582 return;
583 }
584 switch(cur->type) {
585 case XPATH_UNDEFINED:
586 fprintf(output, "Object is uninitialized\n");
587 break;
588 case XPATH_NODESET:
589 fprintf(output, "Object is a Node Set :\n");
590 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
591 break;
592 case XPATH_XSLT_TREE:
593 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000594 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000595 break;
596 case XPATH_BOOLEAN:
597 fprintf(output, "Object is a Boolean : ");
598 if (cur->boolval) fprintf(output, "true\n");
599 else fprintf(output, "false\n");
600 break;
601 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +0000602 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000603 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000604 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000605 break;
606 case -1:
607 fprintf(output, "Object is a number : -Infinity\n");
608 break;
609 default:
Daniel Veillardcda96922001-08-21 10:56:31 +0000610 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000611 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +0000612 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
613 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000614 } else {
615 fprintf(output, "Object is a number : %0g\n", cur->floatval);
616 }
617 }
Owen Taylor3473f882001-02-23 17:55:21 +0000618 break;
619 case XPATH_STRING:
620 fprintf(output, "Object is a string : ");
621 xmlDebugDumpString(output, cur->stringval);
622 fprintf(output, "\n");
623 break;
624 case XPATH_POINT:
625 fprintf(output, "Object is a point : index %d in node", cur->index);
626 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
627 fprintf(output, "\n");
628 break;
629 case XPATH_RANGE:
630 if ((cur->user2 == NULL) ||
631 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
632 fprintf(output, "Object is a collapsed range :\n");
633 fprintf(output, shift);
634 if (cur->index >= 0)
635 fprintf(output, "index %d in ", cur->index);
636 fprintf(output, "node\n");
637 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
638 depth + 1);
639 } else {
640 fprintf(output, "Object is a range :\n");
641 fprintf(output, shift);
642 fprintf(output, "From ");
643 if (cur->index >= 0)
644 fprintf(output, "index %d in ", cur->index);
645 fprintf(output, "node\n");
646 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
647 depth + 1);
648 fprintf(output, shift);
649 fprintf(output, "To ");
650 if (cur->index2 >= 0)
651 fprintf(output, "index %d in ", cur->index2);
652 fprintf(output, "node\n");
653 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
654 depth + 1);
655 fprintf(output, "\n");
656 }
657 break;
658 case XPATH_LOCATIONSET:
659#if defined(LIBXML_XPTR_ENABLED)
660 fprintf(output, "Object is a Location Set:\n");
661 xmlXPathDebugDumpLocationSet(output,
662 (xmlLocationSetPtr) cur->user, depth);
663#endif
664 break;
665 case XPATH_USERS:
666 fprintf(output, "Object is user defined\n");
667 break;
668 }
669}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000670
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000671static void
672xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000673 xmlXPathStepOpPtr op, int depth) {
674 int i;
675 char shift[100];
676
677 for (i = 0;((i < depth) && (i < 25));i++)
678 shift[2 * i] = shift[2 * i + 1] = ' ';
679 shift[2 * i] = shift[2 * i + 1] = 0;
680
681 fprintf(output, shift);
682 if (op == NULL) {
683 fprintf(output, "Step is NULL\n");
684 return;
685 }
686 switch (op->op) {
687 case XPATH_OP_END:
688 fprintf(output, "END"); break;
689 case XPATH_OP_AND:
690 fprintf(output, "AND"); break;
691 case XPATH_OP_OR:
692 fprintf(output, "OR"); break;
693 case XPATH_OP_EQUAL:
694 if (op->value)
695 fprintf(output, "EQUAL =");
696 else
697 fprintf(output, "EQUAL !=");
698 break;
699 case XPATH_OP_CMP:
700 if (op->value)
701 fprintf(output, "CMP <");
702 else
703 fprintf(output, "CMP >");
704 if (!op->value2)
705 fprintf(output, "=");
706 break;
707 case XPATH_OP_PLUS:
708 if (op->value == 0)
709 fprintf(output, "PLUS -");
710 else if (op->value == 1)
711 fprintf(output, "PLUS +");
712 else if (op->value == 2)
713 fprintf(output, "PLUS unary -");
714 else if (op->value == 3)
715 fprintf(output, "PLUS unary - -");
716 break;
717 case XPATH_OP_MULT:
718 if (op->value == 0)
719 fprintf(output, "MULT *");
720 else if (op->value == 1)
721 fprintf(output, "MULT div");
722 else
723 fprintf(output, "MULT mod");
724 break;
725 case XPATH_OP_UNION:
726 fprintf(output, "UNION"); break;
727 case XPATH_OP_ROOT:
728 fprintf(output, "ROOT"); break;
729 case XPATH_OP_NODE:
730 fprintf(output, "NODE"); break;
731 case XPATH_OP_RESET:
732 fprintf(output, "RESET"); break;
733 case XPATH_OP_SORT:
734 fprintf(output, "SORT"); break;
735 case XPATH_OP_COLLECT: {
736 xmlXPathAxisVal axis = op->value;
737 xmlXPathTestVal test = op->value2;
738 xmlXPathTypeVal type = op->value3;
739 const xmlChar *prefix = op->value4;
740 const xmlChar *name = op->value5;
741
742 fprintf(output, "COLLECT ");
743 switch (axis) {
744 case AXIS_ANCESTOR:
745 fprintf(output, " 'ancestors' "); break;
746 case AXIS_ANCESTOR_OR_SELF:
747 fprintf(output, " 'ancestors-or-self' "); break;
748 case AXIS_ATTRIBUTE:
749 fprintf(output, " 'attributes' "); break;
750 case AXIS_CHILD:
751 fprintf(output, " 'child' "); break;
752 case AXIS_DESCENDANT:
753 fprintf(output, " 'descendant' "); break;
754 case AXIS_DESCENDANT_OR_SELF:
755 fprintf(output, " 'descendant-or-self' "); break;
756 case AXIS_FOLLOWING:
757 fprintf(output, " 'following' "); break;
758 case AXIS_FOLLOWING_SIBLING:
759 fprintf(output, " 'following-siblings' "); break;
760 case AXIS_NAMESPACE:
761 fprintf(output, " 'namespace' "); break;
762 case AXIS_PARENT:
763 fprintf(output, " 'parent' "); break;
764 case AXIS_PRECEDING:
765 fprintf(output, " 'preceding' "); break;
766 case AXIS_PRECEDING_SIBLING:
767 fprintf(output, " 'preceding-sibling' "); break;
768 case AXIS_SELF:
769 fprintf(output, " 'self' "); break;
770 }
771 switch (test) {
772 case NODE_TEST_NONE:
773 fprintf(output, "'none' "); break;
774 case NODE_TEST_TYPE:
775 fprintf(output, "'type' "); break;
776 case NODE_TEST_PI:
777 fprintf(output, "'PI' "); break;
778 case NODE_TEST_ALL:
779 fprintf(output, "'all' "); break;
780 case NODE_TEST_NS:
781 fprintf(output, "'namespace' "); break;
782 case NODE_TEST_NAME:
783 fprintf(output, "'name' "); break;
784 }
785 switch (type) {
786 case NODE_TYPE_NODE:
787 fprintf(output, "'node' "); break;
788 case NODE_TYPE_COMMENT:
789 fprintf(output, "'comment' "); break;
790 case NODE_TYPE_TEXT:
791 fprintf(output, "'text' "); break;
792 case NODE_TYPE_PI:
793 fprintf(output, "'PI' "); break;
794 }
795 if (prefix != NULL)
796 fprintf(output, "%s:", prefix);
797 if (name != NULL)
798 fprintf(output, "%s", name);
799 break;
800
801 }
802 case XPATH_OP_VALUE: {
803 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
804
805 fprintf(output, "ELEM ");
806 xmlXPathDebugDumpObject(output, object, 0);
807 goto finish;
808 }
809 case XPATH_OP_VARIABLE: {
810 const xmlChar *prefix = op->value5;
811 const xmlChar *name = op->value4;
812
813 if (prefix != NULL)
814 fprintf(output, "VARIABLE %s:%s", prefix, name);
815 else
816 fprintf(output, "VARIABLE %s", name);
817 break;
818 }
819 case XPATH_OP_FUNCTION: {
820 int nbargs = op->value;
821 const xmlChar *prefix = op->value5;
822 const xmlChar *name = op->value4;
823
824 if (prefix != NULL)
825 fprintf(output, "FUNCTION %s:%s(%d args)",
826 prefix, name, nbargs);
827 else
828 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
829 break;
830 }
831 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
832 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000833 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +0000834#ifdef LIBXML_XPTR_ENABLED
835 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
836#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000837 default:
838 fprintf(output, "UNKNOWN %d\n", op->op); return;
839 }
840 fprintf(output, "\n");
841finish:
842 if (op->ch1 >= 0)
843 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
844 if (op->ch2 >= 0)
845 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
846}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000847
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000848/**
849 * xmlXPathDebugDumpCompExpr:
850 * @output: the FILE * for the output
851 * @comp: the precompiled XPath expression
852 * @depth: the indentation level.
853 *
854 * Dumps the tree of the compiled XPath expression.
855 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000856void
857xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
858 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000859 int i;
860 char shift[100];
861
862 for (i = 0;((i < depth) && (i < 25));i++)
863 shift[2 * i] = shift[2 * i + 1] = ' ';
864 shift[2 * i] = shift[2 * i + 1] = 0;
865
866 fprintf(output, shift);
867
868 if (comp == NULL) {
869 fprintf(output, "Compiled Expression is NULL\n");
870 return;
871 }
872 fprintf(output, "Compiled Expression : %d elements\n",
873 comp->nbStep);
874 i = comp->last;
875 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
876}
Daniel Veillard017b1082001-06-21 11:20:21 +0000877#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000878
879/************************************************************************
880 * *
881 * Parser stacks related functions and macros *
882 * *
883 ************************************************************************/
884
885/*
886 * Generic function for accessing stacks in the Parser Context
887 */
888
889#define PUSH_AND_POP(type, name) \
890extern int name##Push(xmlXPathParserContextPtr ctxt, type value) { \
891 if (ctxt->name##Nr >= ctxt->name##Max) { \
892 ctxt->name##Max *= 2; \
893 ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab, \
894 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
895 if (ctxt->name##Tab == NULL) { \
896 xmlGenericError(xmlGenericErrorContext, \
897 "realloc failed !\n"); \
898 return(0); \
899 } \
900 } \
901 ctxt->name##Tab[ctxt->name##Nr] = value; \
902 ctxt->name = value; \
903 return(ctxt->name##Nr++); \
904} \
905extern type name##Pop(xmlXPathParserContextPtr ctxt) { \
906 type ret; \
907 if (ctxt->name##Nr <= 0) return(0); \
908 ctxt->name##Nr--; \
909 if (ctxt->name##Nr > 0) \
910 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
911 else \
912 ctxt->name = NULL; \
913 ret = ctxt->name##Tab[ctxt->name##Nr]; \
914 ctxt->name##Tab[ctxt->name##Nr] = 0; \
915 return(ret); \
916} \
917
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000918/**
919 * valuePop:
920 * @ctxt: an XPath evaluation context
921 *
922 * Pops the top XPath object from the value stack
923 *
924 * Returns the XPath object just removed
925 */
926/**
927 * valuePush:
928 * @ctxt: an XPath evaluation context
929 * @value: the XPath object
930 *
931 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000932 *
933 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000934 */
Owen Taylor3473f882001-02-23 17:55:21 +0000935PUSH_AND_POP(xmlXPathObjectPtr, value)
936
Thomas Broyerf06a3d82001-07-16 04:52:57 +0000937/**
938 * xmlXPathPopBoolean:
939 * @ctxt: an XPath parser context
940 *
941 * Pops a boolean from the stack, handling conversion if needed.
942 * Check error with #xmlXPathCheckError.
943 *
944 * Returns the boolean
945 */
946int
947xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
948 xmlXPathObjectPtr obj;
949 int ret;
950
951 obj = valuePop(ctxt);
952 if (obj == NULL) {
953 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
954 return(0);
955 }
956 ret = xmlXPathCastToBoolean(obj);
957 xmlXPathFreeObject(obj);
958 return(ret);
959}
960
961/**
962 * xmlXPathPopNumber:
963 * @ctxt: an XPath parser context
964 *
965 * Pops a number from the stack, handling conversion if needed.
966 * Check error with #xmlXPathCheckError.
967 *
968 * Returns the number
969 */
970double
971xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
972 xmlXPathObjectPtr obj;
973 double ret;
974
975 obj = valuePop(ctxt);
976 if (obj == NULL) {
977 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
978 return(0);
979 }
980 ret = xmlXPathCastToNumber(obj);
981 xmlXPathFreeObject(obj);
982 return(ret);
983}
984
985/**
986 * xmlXPathPopString:
987 * @ctxt: an XPath parser context
988 *
989 * Pops a string from the stack, handling conversion if needed.
990 * Check error with #xmlXPathCheckError.
991 *
992 * Returns the string
993 */
994xmlChar *
995xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
996 xmlXPathObjectPtr obj;
997 xmlChar * ret;
998
999 obj = valuePop(ctxt);
1000 if (obj == NULL) {
1001 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1002 return(NULL);
1003 }
1004 ret = xmlXPathCastToString(obj);
1005 /* TODO: needs refactoring somewhere else */
1006 if (obj->stringval == ret)
1007 obj->stringval = NULL;
1008 xmlXPathFreeObject(obj);
1009 return(ret);
1010}
1011
1012/**
1013 * xmlXPathPopNodeSet:
1014 * @ctxt: an XPath parser context
1015 *
1016 * Pops a node-set from the stack, handling conversion if needed.
1017 * Check error with #xmlXPathCheckError.
1018 *
1019 * Returns the node-set
1020 */
1021xmlNodeSetPtr
1022xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
1023 xmlXPathObjectPtr obj;
1024 xmlNodeSetPtr ret;
1025
1026 if (ctxt->value == NULL) {
1027 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1028 return(NULL);
1029 }
1030 if (!xmlXPathStackIsNodeSet(ctxt)) {
1031 xmlXPathSetTypeError(ctxt);
1032 return(NULL);
1033 }
1034 obj = valuePop(ctxt);
1035 ret = obj->nodesetval;
1036 xmlXPathFreeNodeSetList(obj);
1037 return(ret);
1038}
1039
1040/**
1041 * xmlXPathPopExternal:
1042 * @ctxt: an XPath parser context
1043 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001044 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001045 * Check error with #xmlXPathCheckError.
1046 *
1047 * Returns the object
1048 */
1049void *
1050xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1051 xmlXPathObjectPtr obj;
1052 void * ret;
1053
1054 if (ctxt->value == NULL) {
1055 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1056 return(NULL);
1057 }
1058 if (ctxt->value->type != XPATH_USERS) {
1059 xmlXPathSetTypeError(ctxt);
1060 return(NULL);
1061 }
1062 obj = valuePop(ctxt);
1063 ret = obj->user;
1064 xmlXPathFreeObject(obj);
1065 return(ret);
1066}
1067
Owen Taylor3473f882001-02-23 17:55:21 +00001068/*
1069 * Macros for accessing the content. Those should be used only by the parser,
1070 * and not exported.
1071 *
1072 * Dirty macros, i.e. one need to make assumption on the context to use them
1073 *
1074 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1075 * CUR returns the current xmlChar value, i.e. a 8 bit value
1076 * in ISO-Latin or UTF-8.
1077 * This should be used internally by the parser
1078 * only to compare to ASCII values otherwise it would break when
1079 * running with UTF-8 encoding.
1080 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1081 * to compare on ASCII based substring.
1082 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1083 * strings within the parser.
1084 * CURRENT Returns the current char value, with the full decoding of
1085 * UTF-8 if we are using this mode. It returns an int.
1086 * NEXT Skip to the next character, this does the proper decoding
1087 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1088 * It returns the pointer to the current xmlChar.
1089 */
1090
1091#define CUR (*ctxt->cur)
1092#define SKIP(val) ctxt->cur += (val)
1093#define NXT(val) ctxt->cur[(val)]
1094#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001095#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1096
1097#define COPY_BUF(l,b,i,v) \
1098 if (l == 1) b[i++] = (xmlChar) v; \
1099 else i += xmlCopyChar(l,&b[i],v)
1100
1101#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001102
1103#define SKIP_BLANKS \
1104 while (IS_BLANK(*(ctxt->cur))) NEXT
1105
1106#define CURRENT (*ctxt->cur)
1107#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1108
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001109
1110#ifndef DBL_DIG
1111#define DBL_DIG 16
1112#endif
1113#ifndef DBL_EPSILON
1114#define DBL_EPSILON 1E-9
1115#endif
1116
1117#define UPPER_DOUBLE 1E9
1118#define LOWER_DOUBLE 1E-5
1119
1120#define INTEGER_DIGITS DBL_DIG
1121#define FRACTION_DIGITS (DBL_DIG + 1)
1122#define EXPONENT_DIGITS (3 + 2)
1123
1124/**
1125 * xmlXPathFormatNumber:
1126 * @number: number to format
1127 * @buffer: output buffer
1128 * @buffersize: size of output buffer
1129 *
1130 * Convert the number into a string representation.
1131 */
1132static void
1133xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1134{
Daniel Veillardcda96922001-08-21 10:56:31 +00001135 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001136 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001137 if (buffersize > (int)sizeof("Infinity"))
1138 sprintf(buffer, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001139 break;
1140 case -1:
1141 if (buffersize > (int)sizeof("-Infinity"))
1142 sprintf(buffer, "-Infinity");
1143 break;
1144 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001145 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001146 if (buffersize > (int)sizeof("NaN"))
1147 sprintf(buffer, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001148 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
1149 sprintf(buffer, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001150 } else if (number == ((int) number)) {
1151 char work[30];
1152 char *ptr, *cur;
1153 int res, value = (int) number;
1154
1155 ptr = &buffer[0];
1156 if (value < 0) {
1157 *ptr++ = '-';
1158 value = -value;
1159 }
1160 if (value == 0) {
1161 *ptr++ = '0';
1162 } else {
1163 cur = &work[0];
1164 while (value != 0) {
1165 res = value % 10;
1166 value = value / 10;
1167 *cur++ = '0' + res;
1168 }
1169 cur--;
1170 while ((cur >= &work[0]) && (ptr - buffer < buffersize)) {
1171 *ptr++ = *cur--;
1172 }
1173 }
1174 if (ptr - buffer < buffersize) {
1175 *ptr = 0;
1176 } else if (buffersize > 0) {
1177 ptr--;
1178 *ptr = 0;
1179 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001180 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001181 /* 3 is sign, decimal point, and terminating zero */
1182 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1183 int integer_place, fraction_place;
1184 char *ptr;
1185 char *after_fraction;
1186 double absolute_value;
1187 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001188
Bjorn Reese70a9da52001-04-21 16:57:29 +00001189 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001190
Bjorn Reese70a9da52001-04-21 16:57:29 +00001191 /*
1192 * First choose format - scientific or regular floating point.
1193 * In either case, result is in work, and after_fraction points
1194 * just past the fractional part.
1195 */
1196 if ( ((absolute_value > UPPER_DOUBLE) ||
1197 (absolute_value < LOWER_DOUBLE)) &&
1198 (absolute_value != 0.0) ) {
1199 /* Use scientific notation */
1200 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1201 fraction_place = DBL_DIG - 1;
1202 snprintf(work, sizeof(work),"%*.*e",
1203 integer_place, fraction_place, number);
1204 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001205 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001206 else {
1207 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001208 if (absolute_value > 0.0)
1209 integer_place = 1 + (int)log10(absolute_value);
1210 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001211 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001212 fraction_place = (integer_place > 0)
1213 ? DBL_DIG - integer_place
1214 : DBL_DIG;
1215 size = snprintf(work, sizeof(work), "%0.*f",
1216 fraction_place, number);
1217 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001218 }
1219
Bjorn Reese70a9da52001-04-21 16:57:29 +00001220 /* Remove fractional trailing zeroes */
1221 ptr = after_fraction;
1222 while (*(--ptr) == '0')
1223 ;
1224 if (*ptr != '.')
1225 ptr++;
1226 strcpy(ptr, after_fraction);
1227
1228 /* Finally copy result back to caller */
1229 size = strlen(work) + 1;
1230 if (size > buffersize) {
1231 work[buffersize - 1] = 0;
1232 size = buffersize;
1233 }
1234 memcpy(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001235 }
1236 break;
1237 }
1238}
1239
Owen Taylor3473f882001-02-23 17:55:21 +00001240/************************************************************************
1241 * *
1242 * Error handling routines *
1243 * *
1244 ************************************************************************/
1245
1246
Daniel Veillardb44025c2001-10-11 22:55:55 +00001247static const char *xmlXPathErrorMessages[] = {
Owen Taylor3473f882001-02-23 17:55:21 +00001248 "Ok",
1249 "Number encoding",
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001250 "Unfinished literal",
1251 "Start of literal",
Owen Taylor3473f882001-02-23 17:55:21 +00001252 "Expected $ for variable reference",
1253 "Undefined variable",
1254 "Invalid predicate",
1255 "Invalid expression",
1256 "Missing closing curly brace",
1257 "Unregistered function",
1258 "Invalid operand",
1259 "Invalid type",
1260 "Invalid number of arguments",
1261 "Invalid context size",
1262 "Invalid context position",
1263 "Memory allocation error",
1264 "Syntax error",
1265 "Resource error",
1266 "Sub resource error",
Daniel Veillard61d80a22001-04-27 17:13:01 +00001267 "Undefined namespace prefix",
1268 "Encoding error",
1269 "Char out of XML range"
Owen Taylor3473f882001-02-23 17:55:21 +00001270};
1271
1272/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001273 * xmlXPatherror:
Owen Taylor3473f882001-02-23 17:55:21 +00001274 * @ctxt: the XPath Parser context
1275 * @file: the file name
1276 * @line: the line number
1277 * @no: the error number
1278 *
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001279 * Formats an error message.
Owen Taylor3473f882001-02-23 17:55:21 +00001280 */
1281void
Daniel Veillard21458c82002-03-27 16:12:22 +00001282xmlXPatherror(xmlXPathParserContextPtr ctxt, ATTRIBUTE_UNUSED const char *file,
1283 ATTRIBUTE_UNUSED int line, int no) {
Owen Taylor3473f882001-02-23 17:55:21 +00001284 int n;
1285 const xmlChar *cur;
1286 const xmlChar *base;
1287
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001288/* xmlGenericError(xmlGenericErrorContext,
Owen Taylor3473f882001-02-23 17:55:21 +00001289 "Error %s:%d: %s\n", file, line,
1290 xmlXPathErrorMessages[no]);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001291*/
1292 xmlGenericError(xmlGenericErrorContext,
1293 "Error %s\n", xmlXPathErrorMessages[no]);
Owen Taylor3473f882001-02-23 17:55:21 +00001294
1295 cur = ctxt->cur;
1296 base = ctxt->base;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001297 if ((cur == NULL) || (base == NULL))
1298 return;
1299
Owen Taylor3473f882001-02-23 17:55:21 +00001300 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
1301 cur--;
1302 }
1303 n = 0;
1304 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
1305 cur--;
1306 if ((*cur == '\n') || (*cur == '\r')) cur++;
1307 base = cur;
1308 n = 0;
1309 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
1310 xmlGenericError(xmlGenericErrorContext, "%c", (unsigned char) *cur++);
1311 n++;
1312 }
1313 xmlGenericError(xmlGenericErrorContext, "\n");
1314 cur = ctxt->cur;
1315 while ((*cur == '\n') || (*cur == '\r'))
1316 cur--;
1317 n = 0;
1318 while ((cur != base) && (n++ < 80)) {
1319 xmlGenericError(xmlGenericErrorContext, " ");
1320 base++;
1321 }
1322 xmlGenericError(xmlGenericErrorContext,"^\n");
1323}
1324
1325
1326/************************************************************************
1327 * *
1328 * Routines to handle NodeSets *
1329 * *
1330 ************************************************************************/
1331
1332/**
1333 * xmlXPathCmpNodes:
1334 * @node1: the first node
1335 * @node2: the second node
1336 *
1337 * Compare two nodes w.r.t document order
1338 *
1339 * Returns -2 in case of error 1 if first point < second point, 0 if
1340 * that's the same node, -1 otherwise
1341 */
1342int
1343xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1344 int depth1, depth2;
1345 xmlNodePtr cur, root;
1346
1347 if ((node1 == NULL) || (node2 == NULL))
1348 return(-2);
1349 /*
1350 * a couple of optimizations which will avoid computations in most cases
1351 */
1352 if (node1 == node2)
1353 return(0);
Daniel Veillardb33c2012001-04-25 12:59:04 +00001354 if ((node1->type == XML_NAMESPACE_DECL) ||
1355 (node2->type == XML_NAMESPACE_DECL))
1356 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001357 if (node1 == node2->prev)
1358 return(1);
1359 if (node1 == node2->next)
1360 return(-1);
1361
1362 /*
1363 * compute depth to root
1364 */
1365 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1366 if (cur == node1)
1367 return(1);
1368 depth2++;
1369 }
1370 root = cur;
1371 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1372 if (cur == node2)
1373 return(-1);
1374 depth1++;
1375 }
1376 /*
1377 * Distinct document (or distinct entities :-( ) case.
1378 */
1379 if (root != cur) {
1380 return(-2);
1381 }
1382 /*
1383 * get the nearest common ancestor.
1384 */
1385 while (depth1 > depth2) {
1386 depth1--;
1387 node1 = node1->parent;
1388 }
1389 while (depth2 > depth1) {
1390 depth2--;
1391 node2 = node2->parent;
1392 }
1393 while (node1->parent != node2->parent) {
1394 node1 = node1->parent;
1395 node2 = node2->parent;
1396 /* should not happen but just in case ... */
1397 if ((node1 == NULL) || (node2 == NULL))
1398 return(-2);
1399 }
1400 /*
1401 * Find who's first.
1402 */
1403 if (node1 == node2->next)
1404 return(-1);
1405 for (cur = node1->next;cur != NULL;cur = cur->next)
1406 if (cur == node2)
1407 return(1);
1408 return(-1); /* assume there is no sibling list corruption */
1409}
1410
1411/**
1412 * xmlXPathNodeSetSort:
1413 * @set: the node set
1414 *
1415 * Sort the node set in document order
1416 */
1417void
1418xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001419 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001420 xmlNodePtr tmp;
1421
1422 if (set == NULL)
1423 return;
1424
1425 /* Use Shell's sort to sort the node-set */
1426 len = set->nodeNr;
1427 for (incr = len / 2; incr > 0; incr /= 2) {
1428 for (i = incr; i < len; i++) {
1429 j = i - incr;
1430 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001431 if (xmlXPathCmpNodes(set->nodeTab[j],
1432 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001433 tmp = set->nodeTab[j];
1434 set->nodeTab[j] = set->nodeTab[j + incr];
1435 set->nodeTab[j + incr] = tmp;
1436 j -= incr;
1437 } else
1438 break;
1439 }
1440 }
1441 }
1442}
1443
1444#define XML_NODESET_DEFAULT 10
1445/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001446 * xmlXPathNodeSetDupNs:
1447 * @node: the parent node of the namespace XPath node
1448 * @ns: the libxml namespace declaration node.
1449 *
1450 * Namespace node in libxml don't match the XPath semantic. In a node set
1451 * the namespace nodes are duplicated and the next pointer is set to the
1452 * parent node in the XPath semantic.
1453 *
1454 * Returns the newly created object.
1455 */
1456static xmlNodePtr
1457xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
1458 xmlNsPtr cur;
1459
1460 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1461 return(NULL);
1462 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
1463 return((xmlNodePtr) ns);
1464
1465 /*
1466 * Allocate a new Namespace and fill the fields.
1467 */
1468 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1469 if (cur == NULL) {
1470 xmlGenericError(xmlGenericErrorContext,
1471 "xmlXPathNodeSetDupNs : malloc failed\n");
1472 return(NULL);
1473 }
1474 memset(cur, 0, sizeof(xmlNs));
1475 cur->type = XML_NAMESPACE_DECL;
1476 if (ns->href != NULL)
1477 cur->href = xmlStrdup(ns->href);
1478 if (ns->prefix != NULL)
1479 cur->prefix = xmlStrdup(ns->prefix);
1480 cur->next = (xmlNsPtr) node;
1481 return((xmlNodePtr) cur);
1482}
1483
1484/**
1485 * xmlXPathNodeSetFreeNs:
1486 * @ns: the XPath namespace node found in a nodeset.
1487 *
1488 * Namespace node in libxml don't match the XPath semantic. In a node set
1489 * the namespace nodes are duplicated and the next pointer is set to the
1490 * parent node in the XPath semantic. Check if such a node need to be freed
1491 */
1492static void
1493xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
1494 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1495 return;
1496
1497 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
1498 if (ns->href != NULL)
1499 xmlFree((xmlChar *)ns->href);
1500 if (ns->prefix != NULL)
1501 xmlFree((xmlChar *)ns->prefix);
1502 xmlFree(ns);
1503 }
1504}
1505
1506/**
Owen Taylor3473f882001-02-23 17:55:21 +00001507 * xmlXPathNodeSetCreate:
1508 * @val: an initial xmlNodePtr, or NULL
1509 *
1510 * Create a new xmlNodeSetPtr of type double and of value @val
1511 *
1512 * Returns the newly created object.
1513 */
1514xmlNodeSetPtr
1515xmlXPathNodeSetCreate(xmlNodePtr val) {
1516 xmlNodeSetPtr ret;
1517
1518 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1519 if (ret == NULL) {
1520 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001521 "xmlXPathNodeSetCreate: out of memory\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001522 return(NULL);
1523 }
1524 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1525 if (val != NULL) {
1526 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1527 sizeof(xmlNodePtr));
1528 if (ret->nodeTab == NULL) {
1529 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001530 "xmlXPathNodeSetCreate: out of memory\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001531 return(NULL);
1532 }
1533 memset(ret->nodeTab, 0 ,
1534 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1535 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001536 if (val->type == XML_NAMESPACE_DECL) {
1537 xmlNsPtr ns = (xmlNsPtr) val;
1538
1539 ret->nodeTab[ret->nodeNr++] =
1540 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1541 } else
1542 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001543 }
1544 return(ret);
1545}
1546
1547/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001548 * xmlXPathNodeSetContains:
1549 * @cur: the node-set
1550 * @val: the node
1551 *
1552 * checks whether @cur contains @val
1553 *
1554 * Returns true (1) if @cur contains @val, false (0) otherwise
1555 */
1556int
1557xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1558 int i;
1559
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001560 if (val->type == XML_NAMESPACE_DECL) {
1561 for (i = 0; i < cur->nodeNr; i++) {
1562 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1563 xmlNsPtr ns1, ns2;
1564
1565 ns1 = (xmlNsPtr) val;
1566 ns2 = (xmlNsPtr) cur->nodeTab[i];
1567 if (ns1 == ns2)
1568 return(1);
1569 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
1570 (xmlStrEqual(ns1->prefix, ns2->prefix)))
1571 return(1);
1572 }
1573 }
1574 } else {
1575 for (i = 0; i < cur->nodeNr; i++) {
1576 if (cur->nodeTab[i] == val)
1577 return(1);
1578 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001579 }
1580 return(0);
1581}
1582
1583/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001584 * xmlXPathNodeSetAddNs:
1585 * @cur: the initial node set
1586 * @node: the hosting node
1587 * @ns: a the namespace node
1588 *
1589 * add a new namespace node to an existing NodeSet
1590 */
1591static void
1592xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
1593 int i;
1594
1595 if ((ns == NULL) || (node == NULL) || (ns->type != XML_NAMESPACE_DECL) ||
1596 (node->type != XML_ELEMENT_NODE))
1597 return;
1598
1599 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1600 /*
1601 * check against doublons
1602 */
1603 for (i = 0;i < cur->nodeNr;i++) {
1604 if ((cur->nodeTab[i] != NULL) &&
1605 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00001606 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001607 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
1608 return;
1609 }
1610
1611 /*
1612 * grow the nodeTab if needed
1613 */
1614 if (cur->nodeMax == 0) {
1615 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1616 sizeof(xmlNodePtr));
1617 if (cur->nodeTab == NULL) {
1618 xmlGenericError(xmlGenericErrorContext,
1619 "xmlXPathNodeSetAdd: out of memory\n");
1620 return;
1621 }
1622 memset(cur->nodeTab, 0 ,
1623 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1624 cur->nodeMax = XML_NODESET_DEFAULT;
1625 } else if (cur->nodeNr == cur->nodeMax) {
1626 xmlNodePtr *temp;
1627
1628 cur->nodeMax *= 2;
1629 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1630 sizeof(xmlNodePtr));
1631 if (temp == NULL) {
1632 xmlGenericError(xmlGenericErrorContext,
1633 "xmlXPathNodeSetAdd: out of memory\n");
1634 return;
1635 }
1636 cur->nodeTab = temp;
1637 }
1638 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
1639}
1640
1641/**
Owen Taylor3473f882001-02-23 17:55:21 +00001642 * xmlXPathNodeSetAdd:
1643 * @cur: the initial node set
1644 * @val: a new xmlNodePtr
1645 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001646 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00001647 */
1648void
1649xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1650 int i;
1651
1652 if (val == NULL) return;
1653
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001654 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001655 /*
1656 * check against doublons
1657 */
1658 for (i = 0;i < cur->nodeNr;i++)
1659 if (cur->nodeTab[i] == val) return;
1660
1661 /*
1662 * grow the nodeTab if needed
1663 */
1664 if (cur->nodeMax == 0) {
1665 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1666 sizeof(xmlNodePtr));
1667 if (cur->nodeTab == NULL) {
1668 xmlGenericError(xmlGenericErrorContext,
1669 "xmlXPathNodeSetAdd: out of memory\n");
1670 return;
1671 }
1672 memset(cur->nodeTab, 0 ,
1673 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1674 cur->nodeMax = XML_NODESET_DEFAULT;
1675 } else if (cur->nodeNr == cur->nodeMax) {
1676 xmlNodePtr *temp;
1677
1678 cur->nodeMax *= 2;
1679 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1680 sizeof(xmlNodePtr));
1681 if (temp == NULL) {
1682 xmlGenericError(xmlGenericErrorContext,
1683 "xmlXPathNodeSetAdd: out of memory\n");
1684 return;
1685 }
1686 cur->nodeTab = temp;
1687 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001688 if (val->type == XML_NAMESPACE_DECL) {
1689 xmlNsPtr ns = (xmlNsPtr) val;
1690
1691 cur->nodeTab[cur->nodeNr++] =
1692 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1693 } else
1694 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001695}
1696
1697/**
1698 * xmlXPathNodeSetAddUnique:
1699 * @cur: the initial node set
1700 * @val: a new xmlNodePtr
1701 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001702 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00001703 * when we are sure the node is not already in the set.
1704 */
1705void
1706xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1707 if (val == NULL) return;
1708
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001709 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001710 /*
1711 * grow the nodeTab if needed
1712 */
1713 if (cur->nodeMax == 0) {
1714 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1715 sizeof(xmlNodePtr));
1716 if (cur->nodeTab == NULL) {
1717 xmlGenericError(xmlGenericErrorContext,
1718 "xmlXPathNodeSetAddUnique: out of memory\n");
1719 return;
1720 }
1721 memset(cur->nodeTab, 0 ,
1722 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1723 cur->nodeMax = XML_NODESET_DEFAULT;
1724 } else if (cur->nodeNr == cur->nodeMax) {
1725 xmlNodePtr *temp;
1726
1727 cur->nodeMax *= 2;
1728 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1729 sizeof(xmlNodePtr));
1730 if (temp == NULL) {
1731 xmlGenericError(xmlGenericErrorContext,
1732 "xmlXPathNodeSetAddUnique: out of memory\n");
1733 return;
1734 }
1735 cur->nodeTab = temp;
1736 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001737 if (val->type == XML_NAMESPACE_DECL) {
1738 xmlNsPtr ns = (xmlNsPtr) val;
1739
1740 cur->nodeTab[cur->nodeNr++] =
1741 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1742 } else
1743 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001744}
1745
1746/**
1747 * xmlXPathNodeSetMerge:
1748 * @val1: the first NodeSet or NULL
1749 * @val2: the second NodeSet
1750 *
1751 * Merges two nodesets, all nodes from @val2 are added to @val1
1752 * if @val1 is NULL, a new set is created and copied from @val2
1753 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001754 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00001755 */
1756xmlNodeSetPtr
1757xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001758 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001759
1760 if (val2 == NULL) return(val1);
1761 if (val1 == NULL) {
1762 val1 = xmlXPathNodeSetCreate(NULL);
1763 }
1764
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001765 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001766 initNr = val1->nodeNr;
1767
1768 for (i = 0;i < val2->nodeNr;i++) {
1769 /*
1770 * check against doublons
1771 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001772 skip = 0;
1773 for (j = 0; j < initNr; j++) {
1774 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1775 skip = 1;
1776 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001777 } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) &&
1778 (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) {
1779 xmlNsPtr ns1, ns2;
1780 ns1 = (xmlNsPtr) val1->nodeTab[j];
1781 ns2 = (xmlNsPtr) val2->nodeTab[i];
1782 if ((ns1->next == ns2->next) &&
1783 (xmlStrEqual(ns1->prefix, ns2->prefix))) {
1784 skip = 1;
1785 break;
1786 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001787 }
1788 }
1789 if (skip)
1790 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00001791
1792 /*
1793 * grow the nodeTab if needed
1794 */
1795 if (val1->nodeMax == 0) {
1796 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1797 sizeof(xmlNodePtr));
1798 if (val1->nodeTab == NULL) {
1799 xmlGenericError(xmlGenericErrorContext,
1800 "xmlXPathNodeSetMerge: out of memory\n");
1801 return(NULL);
1802 }
1803 memset(val1->nodeTab, 0 ,
1804 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1805 val1->nodeMax = XML_NODESET_DEFAULT;
1806 } else if (val1->nodeNr == val1->nodeMax) {
1807 xmlNodePtr *temp;
1808
1809 val1->nodeMax *= 2;
1810 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1811 sizeof(xmlNodePtr));
1812 if (temp == NULL) {
1813 xmlGenericError(xmlGenericErrorContext,
1814 "xmlXPathNodeSetMerge: out of memory\n");
1815 return(NULL);
1816 }
1817 val1->nodeTab = temp;
1818 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001819 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1820 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1821
1822 val1->nodeTab[val1->nodeNr++] =
1823 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1824 } else
1825 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00001826 }
1827
1828 return(val1);
1829}
1830
1831/**
Daniel Veillard75be0132002-03-13 10:03:35 +00001832 * xmlXPathNodeSetMergeUnique:
1833 * @val1: the first NodeSet or NULL
1834 * @val2: the second NodeSet
1835 *
1836 * Merges two nodesets, all nodes from @val2 are added to @val1
1837 * if @val1 is NULL, a new set is created and copied from @val2
1838 *
1839 * Returns @val1 once extended or NULL in case of error.
1840 */
1841static xmlNodeSetPtr
1842xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
1843 int i, initNr;
1844
1845 if (val2 == NULL) return(val1);
1846 if (val1 == NULL) {
1847 val1 = xmlXPathNodeSetCreate(NULL);
1848 }
1849
1850 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1851 initNr = val1->nodeNr;
1852
1853 for (i = 0;i < val2->nodeNr;i++) {
1854 /*
1855 * grow the nodeTab if needed
1856 */
1857 if (val1->nodeMax == 0) {
1858 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1859 sizeof(xmlNodePtr));
1860 if (val1->nodeTab == NULL) {
1861 xmlGenericError(xmlGenericErrorContext,
1862 "xmlXPathNodeSetMerge: out of memory\n");
1863 return(NULL);
1864 }
1865 memset(val1->nodeTab, 0 ,
1866 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1867 val1->nodeMax = XML_NODESET_DEFAULT;
1868 } else if (val1->nodeNr == val1->nodeMax) {
1869 xmlNodePtr *temp;
1870
1871 val1->nodeMax *= 2;
1872 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1873 sizeof(xmlNodePtr));
1874 if (temp == NULL) {
1875 xmlGenericError(xmlGenericErrorContext,
1876 "xmlXPathNodeSetMerge: out of memory\n");
1877 return(NULL);
1878 }
1879 val1->nodeTab = temp;
1880 }
1881 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1882 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1883
1884 val1->nodeTab[val1->nodeNr++] =
1885 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1886 } else
1887 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
1888 }
1889
1890 return(val1);
1891}
1892
1893/**
Owen Taylor3473f882001-02-23 17:55:21 +00001894 * xmlXPathNodeSetDel:
1895 * @cur: the initial node set
1896 * @val: an xmlNodePtr
1897 *
1898 * Removes an xmlNodePtr from an existing NodeSet
1899 */
1900void
1901xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
1902 int i;
1903
1904 if (cur == NULL) return;
1905 if (val == NULL) return;
1906
1907 /*
1908 * check against doublons
1909 */
1910 for (i = 0;i < cur->nodeNr;i++)
1911 if (cur->nodeTab[i] == val) break;
1912
1913 if (i >= cur->nodeNr) {
1914#ifdef DEBUG
1915 xmlGenericError(xmlGenericErrorContext,
1916 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
1917 val->name);
1918#endif
1919 return;
1920 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001921 if ((cur->nodeTab[i] != NULL) &&
1922 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
1923 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001924 cur->nodeNr--;
1925 for (;i < cur->nodeNr;i++)
1926 cur->nodeTab[i] = cur->nodeTab[i + 1];
1927 cur->nodeTab[cur->nodeNr] = NULL;
1928}
1929
1930/**
1931 * xmlXPathNodeSetRemove:
1932 * @cur: the initial node set
1933 * @val: the index to remove
1934 *
1935 * Removes an entry from an existing NodeSet list.
1936 */
1937void
1938xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
1939 if (cur == NULL) return;
1940 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001941 if ((cur->nodeTab[val] != NULL) &&
1942 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
1943 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00001944 cur->nodeNr--;
1945 for (;val < cur->nodeNr;val++)
1946 cur->nodeTab[val] = cur->nodeTab[val + 1];
1947 cur->nodeTab[cur->nodeNr] = NULL;
1948}
1949
1950/**
1951 * xmlXPathFreeNodeSet:
1952 * @obj: the xmlNodeSetPtr to free
1953 *
1954 * Free the NodeSet compound (not the actual nodes !).
1955 */
1956void
1957xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
1958 if (obj == NULL) return;
1959 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001960 int i;
1961
1962 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1963 for (i = 0;i < obj->nodeNr;i++)
1964 if ((obj->nodeTab[i] != NULL) &&
1965 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
1966 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001967 xmlFree(obj->nodeTab);
1968 }
Owen Taylor3473f882001-02-23 17:55:21 +00001969 xmlFree(obj);
1970}
1971
1972/**
1973 * xmlXPathFreeValueTree:
1974 * @obj: the xmlNodeSetPtr to free
1975 *
1976 * Free the NodeSet compound and the actual tree, this is different
1977 * from xmlXPathFreeNodeSet()
1978 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001979static void
Owen Taylor3473f882001-02-23 17:55:21 +00001980xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
1981 int i;
1982
1983 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001984
1985 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001986 for (i = 0;i < obj->nodeNr;i++) {
1987 if (obj->nodeTab[i] != NULL) {
1988 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1989 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
1990 } else {
1991 xmlFreeNodeList(obj->nodeTab[i]);
1992 }
1993 }
1994 }
Owen Taylor3473f882001-02-23 17:55:21 +00001995 xmlFree(obj->nodeTab);
1996 }
Owen Taylor3473f882001-02-23 17:55:21 +00001997 xmlFree(obj);
1998}
1999
2000#if defined(DEBUG) || defined(DEBUG_STEP)
2001/**
2002 * xmlGenericErrorContextNodeSet:
2003 * @output: a FILE * for the output
2004 * @obj: the xmlNodeSetPtr to free
2005 *
2006 * Quick display of a NodeSet
2007 */
2008void
2009xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
2010 int i;
2011
2012 if (output == NULL) output = xmlGenericErrorContext;
2013 if (obj == NULL) {
2014 fprintf(output, "NodeSet == NULL !\n");
2015 return;
2016 }
2017 if (obj->nodeNr == 0) {
2018 fprintf(output, "NodeSet is empty\n");
2019 return;
2020 }
2021 if (obj->nodeTab == NULL) {
2022 fprintf(output, " nodeTab == NULL !\n");
2023 return;
2024 }
2025 for (i = 0; i < obj->nodeNr; i++) {
2026 if (obj->nodeTab[i] == NULL) {
2027 fprintf(output, " NULL !\n");
2028 return;
2029 }
2030 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
2031 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
2032 fprintf(output, " /");
2033 else if (obj->nodeTab[i]->name == NULL)
2034 fprintf(output, " noname!");
2035 else fprintf(output, " %s", obj->nodeTab[i]->name);
2036 }
2037 fprintf(output, "\n");
2038}
2039#endif
2040
2041/**
2042 * xmlXPathNewNodeSet:
2043 * @val: the NodePtr value
2044 *
2045 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2046 * it with the single Node @val
2047 *
2048 * Returns the newly created object.
2049 */
2050xmlXPathObjectPtr
2051xmlXPathNewNodeSet(xmlNodePtr val) {
2052 xmlXPathObjectPtr ret;
2053
2054 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2055 if (ret == NULL) {
2056 xmlGenericError(xmlGenericErrorContext,
2057 "xmlXPathNewNodeSet: out of memory\n");
2058 return(NULL);
2059 }
2060 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2061 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00002062 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002063 ret->nodesetval = xmlXPathNodeSetCreate(val);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002064 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002065 return(ret);
2066}
2067
2068/**
2069 * xmlXPathNewValueTree:
2070 * @val: the NodePtr value
2071 *
2072 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
2073 * it with the tree root @val
2074 *
2075 * Returns the newly created object.
2076 */
2077xmlXPathObjectPtr
2078xmlXPathNewValueTree(xmlNodePtr val) {
2079 xmlXPathObjectPtr ret;
2080
2081 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2082 if (ret == NULL) {
2083 xmlGenericError(xmlGenericErrorContext,
2084 "xmlXPathNewNodeSet: out of memory\n");
2085 return(NULL);
2086 }
2087 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2088 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002089 ret->boolval = 1;
2090 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00002091 ret->nodesetval = xmlXPathNodeSetCreate(val);
2092 return(ret);
2093}
2094
2095/**
2096 * xmlXPathNewNodeSetList:
2097 * @val: an existing NodeSet
2098 *
2099 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2100 * it with the Nodeset @val
2101 *
2102 * Returns the newly created object.
2103 */
2104xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002105xmlXPathNewNodeSetList(xmlNodeSetPtr val)
2106{
Owen Taylor3473f882001-02-23 17:55:21 +00002107 xmlXPathObjectPtr ret;
2108 int i;
2109
2110 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002111 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002112 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002113 ret = xmlXPathNewNodeSet(NULL);
2114 else {
2115 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
2116 for (i = 1; i < val->nodeNr; ++i)
2117 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2118 }
Owen Taylor3473f882001-02-23 17:55:21 +00002119
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002120 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002121}
2122
2123/**
2124 * xmlXPathWrapNodeSet:
2125 * @val: the NodePtr value
2126 *
2127 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2128 *
2129 * Returns the newly created object.
2130 */
2131xmlXPathObjectPtr
2132xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2133 xmlXPathObjectPtr ret;
2134
2135 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2136 if (ret == NULL) {
2137 xmlGenericError(xmlGenericErrorContext,
2138 "xmlXPathWrapNodeSet: out of memory\n");
2139 return(NULL);
2140 }
2141 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2142 ret->type = XPATH_NODESET;
2143 ret->nodesetval = val;
2144 return(ret);
2145}
2146
2147/**
2148 * xmlXPathFreeNodeSetList:
2149 * @obj: an existing NodeSetList object
2150 *
2151 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2152 * the list contrary to xmlXPathFreeObject().
2153 */
2154void
2155xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2156 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002157 xmlFree(obj);
2158}
2159
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002160/**
2161 * xmlXPathDifference:
2162 * @nodes1: a node-set
2163 * @nodes2: a node-set
2164 *
2165 * Implements the EXSLT - Sets difference() function:
2166 * node-set set:difference (node-set, node-set)
2167 *
2168 * Returns the difference between the two node sets, or nodes1 if
2169 * nodes2 is empty
2170 */
2171xmlNodeSetPtr
2172xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2173 xmlNodeSetPtr ret;
2174 int i, l1;
2175 xmlNodePtr cur;
2176
2177 if (xmlXPathNodeSetIsEmpty(nodes2))
2178 return(nodes1);
2179
2180 ret = xmlXPathNodeSetCreate(NULL);
2181 if (xmlXPathNodeSetIsEmpty(nodes1))
2182 return(ret);
2183
2184 l1 = xmlXPathNodeSetGetLength(nodes1);
2185
2186 for (i = 0; i < l1; i++) {
2187 cur = xmlXPathNodeSetItem(nodes1, i);
2188 if (!xmlXPathNodeSetContains(nodes2, cur))
2189 xmlXPathNodeSetAddUnique(ret, cur);
2190 }
2191 return(ret);
2192}
2193
2194/**
2195 * xmlXPathIntersection:
2196 * @nodes1: a node-set
2197 * @nodes2: a node-set
2198 *
2199 * Implements the EXSLT - Sets intersection() function:
2200 * node-set set:intersection (node-set, node-set)
2201 *
2202 * Returns a node set comprising the nodes that are within both the
2203 * node sets passed as arguments
2204 */
2205xmlNodeSetPtr
2206xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2207 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2208 int i, l1;
2209 xmlNodePtr cur;
2210
2211 if (xmlXPathNodeSetIsEmpty(nodes1))
2212 return(ret);
2213 if (xmlXPathNodeSetIsEmpty(nodes2))
2214 return(ret);
2215
2216 l1 = xmlXPathNodeSetGetLength(nodes1);
2217
2218 for (i = 0; i < l1; i++) {
2219 cur = xmlXPathNodeSetItem(nodes1, i);
2220 if (xmlXPathNodeSetContains(nodes2, cur))
2221 xmlXPathNodeSetAddUnique(ret, cur);
2222 }
2223 return(ret);
2224}
2225
2226/**
2227 * xmlXPathDistinctSorted:
2228 * @nodes: a node-set, sorted by document order
2229 *
2230 * Implements the EXSLT - Sets distinct() function:
2231 * node-set set:distinct (node-set)
2232 *
2233 * Returns a subset of the nodes contained in @nodes, or @nodes if
2234 * it is empty
2235 */
2236xmlNodeSetPtr
2237xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2238 xmlNodeSetPtr ret;
2239 xmlHashTablePtr hash;
2240 int i, l;
2241 xmlChar * strval;
2242 xmlNodePtr cur;
2243
2244 if (xmlXPathNodeSetIsEmpty(nodes))
2245 return(nodes);
2246
2247 ret = xmlXPathNodeSetCreate(NULL);
2248 l = xmlXPathNodeSetGetLength(nodes);
2249 hash = xmlHashCreate (l);
2250 for (i = 0; i < l; i++) {
2251 cur = xmlXPathNodeSetItem(nodes, i);
2252 strval = xmlXPathCastNodeToString(cur);
2253 if (xmlHashLookup(hash, strval) == NULL) {
2254 xmlHashAddEntry(hash, strval, strval);
2255 xmlXPathNodeSetAddUnique(ret, cur);
2256 } else {
2257 xmlFree(strval);
2258 }
2259 }
2260 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2261 return(ret);
2262}
2263
2264/**
2265 * xmlXPathDistinct:
2266 * @nodes: a node-set
2267 *
2268 * Implements the EXSLT - Sets distinct() function:
2269 * node-set set:distinct (node-set)
2270 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2271 * is called with the sorted node-set
2272 *
2273 * Returns a subset of the nodes contained in @nodes, or @nodes if
2274 * it is empty
2275 */
2276xmlNodeSetPtr
2277xmlXPathDistinct (xmlNodeSetPtr nodes) {
2278 if (xmlXPathNodeSetIsEmpty(nodes))
2279 return(nodes);
2280
2281 xmlXPathNodeSetSort(nodes);
2282 return(xmlXPathDistinctSorted(nodes));
2283}
2284
2285/**
2286 * xmlXPathHasSameNodes:
2287 * @nodes1: a node-set
2288 * @nodes2: a node-set
2289 *
2290 * Implements the EXSLT - Sets has-same-nodes function:
2291 * boolean set:has-same-node(node-set, node-set)
2292 *
2293 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2294 * otherwise
2295 */
2296int
2297xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2298 int i, l;
2299 xmlNodePtr cur;
2300
2301 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2302 xmlXPathNodeSetIsEmpty(nodes2))
2303 return(0);
2304
2305 l = xmlXPathNodeSetGetLength(nodes1);
2306 for (i = 0; i < l; i++) {
2307 cur = xmlXPathNodeSetItem(nodes1, i);
2308 if (xmlXPathNodeSetContains(nodes2, cur))
2309 return(1);
2310 }
2311 return(0);
2312}
2313
2314/**
2315 * xmlXPathNodeLeadingSorted:
2316 * @nodes: a node-set, sorted by document order
2317 * @node: a node
2318 *
2319 * Implements the EXSLT - Sets leading() function:
2320 * node-set set:leading (node-set, node-set)
2321 *
2322 * Returns the nodes in @nodes that precede @node in document order,
2323 * @nodes if @node is NULL or an empty node-set if @nodes
2324 * doesn't contain @node
2325 */
2326xmlNodeSetPtr
2327xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2328 int i, l;
2329 xmlNodePtr cur;
2330 xmlNodeSetPtr ret;
2331
2332 if (node == NULL)
2333 return(nodes);
2334
2335 ret = xmlXPathNodeSetCreate(NULL);
2336 if (xmlXPathNodeSetIsEmpty(nodes) ||
2337 (!xmlXPathNodeSetContains(nodes, node)))
2338 return(ret);
2339
2340 l = xmlXPathNodeSetGetLength(nodes);
2341 for (i = 0; i < l; i++) {
2342 cur = xmlXPathNodeSetItem(nodes, i);
2343 if (cur == node)
2344 break;
2345 xmlXPathNodeSetAddUnique(ret, cur);
2346 }
2347 return(ret);
2348}
2349
2350/**
2351 * xmlXPathNodeLeading:
2352 * @nodes: a node-set
2353 * @node: a node
2354 *
2355 * Implements the EXSLT - Sets leading() function:
2356 * node-set set:leading (node-set, node-set)
2357 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2358 * is called.
2359 *
2360 * Returns the nodes in @nodes that precede @node in document order,
2361 * @nodes if @node is NULL or an empty node-set if @nodes
2362 * doesn't contain @node
2363 */
2364xmlNodeSetPtr
2365xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2366 xmlXPathNodeSetSort(nodes);
2367 return(xmlXPathNodeLeadingSorted(nodes, node));
2368}
2369
2370/**
2371 * xmlXPathLeadingSorted:
2372 * @nodes1: a node-set, sorted by document order
2373 * @nodes2: a node-set, sorted by document order
2374 *
2375 * Implements the EXSLT - Sets leading() function:
2376 * node-set set:leading (node-set, node-set)
2377 *
2378 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2379 * in document order, @nodes1 if @nodes2 is NULL or empty or
2380 * an empty node-set if @nodes1 doesn't contain @nodes2
2381 */
2382xmlNodeSetPtr
2383xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2384 if (xmlXPathNodeSetIsEmpty(nodes2))
2385 return(nodes1);
2386 return(xmlXPathNodeLeadingSorted(nodes1,
2387 xmlXPathNodeSetItem(nodes2, 1)));
2388}
2389
2390/**
2391 * xmlXPathLeading:
2392 * @nodes1: a node-set
2393 * @nodes2: a node-set
2394 *
2395 * Implements the EXSLT - Sets leading() function:
2396 * node-set set:leading (node-set, node-set)
2397 * @nodes1 and @nodes2 are sorted by document order, then
2398 * #exslSetsLeadingSorted is called.
2399 *
2400 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2401 * in document order, @nodes1 if @nodes2 is NULL or empty or
2402 * an empty node-set if @nodes1 doesn't contain @nodes2
2403 */
2404xmlNodeSetPtr
2405xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2406 if (xmlXPathNodeSetIsEmpty(nodes2))
2407 return(nodes1);
2408 if (xmlXPathNodeSetIsEmpty(nodes1))
2409 return(xmlXPathNodeSetCreate(NULL));
2410 xmlXPathNodeSetSort(nodes1);
2411 xmlXPathNodeSetSort(nodes2);
2412 return(xmlXPathNodeLeadingSorted(nodes1,
2413 xmlXPathNodeSetItem(nodes2, 1)));
2414}
2415
2416/**
2417 * xmlXPathNodeTrailingSorted:
2418 * @nodes: a node-set, sorted by document order
2419 * @node: a node
2420 *
2421 * Implements the EXSLT - Sets trailing() function:
2422 * node-set set:trailing (node-set, node-set)
2423 *
2424 * Returns the nodes in @nodes that follow @node in document order,
2425 * @nodes if @node is NULL or an empty node-set if @nodes
2426 * doesn't contain @node
2427 */
2428xmlNodeSetPtr
2429xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2430 int i, l;
2431 xmlNodePtr cur;
2432 xmlNodeSetPtr ret;
2433
2434 if (node == NULL)
2435 return(nodes);
2436
2437 ret = xmlXPathNodeSetCreate(NULL);
2438 if (xmlXPathNodeSetIsEmpty(nodes) ||
2439 (!xmlXPathNodeSetContains(nodes, node)))
2440 return(ret);
2441
2442 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002443 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002444 cur = xmlXPathNodeSetItem(nodes, i);
2445 if (cur == node)
2446 break;
2447 xmlXPathNodeSetAddUnique(ret, cur);
2448 }
2449 return(ret);
2450}
2451
2452/**
2453 * xmlXPathNodeTrailing:
2454 * @nodes: a node-set
2455 * @node: a node
2456 *
2457 * Implements the EXSLT - Sets trailing() function:
2458 * node-set set:trailing (node-set, node-set)
2459 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2460 * is called.
2461 *
2462 * Returns the nodes in @nodes that follow @node in document order,
2463 * @nodes if @node is NULL or an empty node-set if @nodes
2464 * doesn't contain @node
2465 */
2466xmlNodeSetPtr
2467xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2468 xmlXPathNodeSetSort(nodes);
2469 return(xmlXPathNodeTrailingSorted(nodes, node));
2470}
2471
2472/**
2473 * xmlXPathTrailingSorted:
2474 * @nodes1: a node-set, sorted by document order
2475 * @nodes2: a node-set, sorted by document order
2476 *
2477 * Implements the EXSLT - Sets trailing() function:
2478 * node-set set:trailing (node-set, node-set)
2479 *
2480 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2481 * in document order, @nodes1 if @nodes2 is NULL or empty or
2482 * an empty node-set if @nodes1 doesn't contain @nodes2
2483 */
2484xmlNodeSetPtr
2485xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2486 if (xmlXPathNodeSetIsEmpty(nodes2))
2487 return(nodes1);
2488 return(xmlXPathNodeTrailingSorted(nodes1,
2489 xmlXPathNodeSetItem(nodes2, 0)));
2490}
2491
2492/**
2493 * xmlXPathTrailing:
2494 * @nodes1: a node-set
2495 * @nodes2: a node-set
2496 *
2497 * Implements the EXSLT - Sets trailing() function:
2498 * node-set set:trailing (node-set, node-set)
2499 * @nodes1 and @nodes2 are sorted by document order, then
2500 * #xmlXPathTrailingSorted is called.
2501 *
2502 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2503 * in document order, @nodes1 if @nodes2 is NULL or empty or
2504 * an empty node-set if @nodes1 doesn't contain @nodes2
2505 */
2506xmlNodeSetPtr
2507xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2508 if (xmlXPathNodeSetIsEmpty(nodes2))
2509 return(nodes1);
2510 if (xmlXPathNodeSetIsEmpty(nodes1))
2511 return(xmlXPathNodeSetCreate(NULL));
2512 xmlXPathNodeSetSort(nodes1);
2513 xmlXPathNodeSetSort(nodes2);
2514 return(xmlXPathNodeTrailingSorted(nodes1,
2515 xmlXPathNodeSetItem(nodes2, 0)));
2516}
2517
Owen Taylor3473f882001-02-23 17:55:21 +00002518/************************************************************************
2519 * *
2520 * Routines to handle extra functions *
2521 * *
2522 ************************************************************************/
2523
2524/**
2525 * xmlXPathRegisterFunc:
2526 * @ctxt: the XPath context
2527 * @name: the function name
2528 * @f: the function implementation or NULL
2529 *
2530 * Register a new function. If @f is NULL it unregisters the function
2531 *
2532 * Returns 0 in case of success, -1 in case of error
2533 */
2534int
2535xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2536 xmlXPathFunction f) {
2537 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2538}
2539
2540/**
2541 * xmlXPathRegisterFuncNS:
2542 * @ctxt: the XPath context
2543 * @name: the function name
2544 * @ns_uri: the function namespace URI
2545 * @f: the function implementation or NULL
2546 *
2547 * Register a new function. If @f is NULL it unregisters the function
2548 *
2549 * Returns 0 in case of success, -1 in case of error
2550 */
2551int
2552xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2553 const xmlChar *ns_uri, xmlXPathFunction f) {
2554 if (ctxt == NULL)
2555 return(-1);
2556 if (name == NULL)
2557 return(-1);
2558
2559 if (ctxt->funcHash == NULL)
2560 ctxt->funcHash = xmlHashCreate(0);
2561 if (ctxt->funcHash == NULL)
2562 return(-1);
2563 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2564}
2565
2566/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002567 * xmlXPathRegisterFuncLookup:
2568 * @ctxt: the XPath context
2569 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002570 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00002571 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002572 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00002573 */
2574void
2575xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2576 xmlXPathFuncLookupFunc f,
2577 void *funcCtxt) {
2578 if (ctxt == NULL)
2579 return;
2580 ctxt->funcLookupFunc = (void *) f;
2581 ctxt->funcLookupData = funcCtxt;
2582}
2583
2584/**
Owen Taylor3473f882001-02-23 17:55:21 +00002585 * xmlXPathFunctionLookup:
2586 * @ctxt: the XPath context
2587 * @name: the function name
2588 *
2589 * Search in the Function array of the context for the given
2590 * function.
2591 *
2592 * Returns the xmlXPathFunction or NULL if not found
2593 */
2594xmlXPathFunction
2595xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002596 if (ctxt == NULL)
2597 return (NULL);
2598
2599 if (ctxt->funcLookupFunc != NULL) {
2600 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002601 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002602
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002603 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002604 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002605 if (ret != NULL)
2606 return(ret);
2607 }
Owen Taylor3473f882001-02-23 17:55:21 +00002608 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2609}
2610
2611/**
2612 * xmlXPathFunctionLookupNS:
2613 * @ctxt: the XPath context
2614 * @name: the function name
2615 * @ns_uri: the function namespace URI
2616 *
2617 * Search in the Function array of the context for the given
2618 * function.
2619 *
2620 * Returns the xmlXPathFunction or NULL if not found
2621 */
2622xmlXPathFunction
2623xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2624 const xmlChar *ns_uri) {
2625 if (ctxt == NULL)
2626 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002627 if (name == NULL)
2628 return(NULL);
2629
Thomas Broyerba4ad322001-07-26 16:55:21 +00002630 if (ctxt->funcLookupFunc != NULL) {
2631 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002632 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002633
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002634 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002635 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002636 if (ret != NULL)
2637 return(ret);
2638 }
2639
2640 if (ctxt->funcHash == NULL)
2641 return(NULL);
2642
Owen Taylor3473f882001-02-23 17:55:21 +00002643 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2644}
2645
2646/**
2647 * xmlXPathRegisteredFuncsCleanup:
2648 * @ctxt: the XPath context
2649 *
2650 * Cleanup the XPath context data associated to registered functions
2651 */
2652void
2653xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2654 if (ctxt == NULL)
2655 return;
2656
2657 xmlHashFree(ctxt->funcHash, NULL);
2658 ctxt->funcHash = NULL;
2659}
2660
2661/************************************************************************
2662 * *
2663 * Routines to handle Variable *
2664 * *
2665 ************************************************************************/
2666
2667/**
2668 * xmlXPathRegisterVariable:
2669 * @ctxt: the XPath context
2670 * @name: the variable name
2671 * @value: the variable value or NULL
2672 *
2673 * Register a new variable value. If @value is NULL it unregisters
2674 * the variable
2675 *
2676 * Returns 0 in case of success, -1 in case of error
2677 */
2678int
2679xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2680 xmlXPathObjectPtr value) {
2681 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2682}
2683
2684/**
2685 * xmlXPathRegisterVariableNS:
2686 * @ctxt: the XPath context
2687 * @name: the variable name
2688 * @ns_uri: the variable namespace URI
2689 * @value: the variable value or NULL
2690 *
2691 * Register a new variable value. If @value is NULL it unregisters
2692 * the variable
2693 *
2694 * Returns 0 in case of success, -1 in case of error
2695 */
2696int
2697xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2698 const xmlChar *ns_uri,
2699 xmlXPathObjectPtr value) {
2700 if (ctxt == NULL)
2701 return(-1);
2702 if (name == NULL)
2703 return(-1);
2704
2705 if (ctxt->varHash == NULL)
2706 ctxt->varHash = xmlHashCreate(0);
2707 if (ctxt->varHash == NULL)
2708 return(-1);
2709 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2710 (void *) value,
2711 (xmlHashDeallocator)xmlXPathFreeObject));
2712}
2713
2714/**
2715 * xmlXPathRegisterVariableLookup:
2716 * @ctxt: the XPath context
2717 * @f: the lookup function
2718 * @data: the lookup data
2719 *
2720 * register an external mechanism to do variable lookup
2721 */
2722void
2723xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2724 xmlXPathVariableLookupFunc f, void *data) {
2725 if (ctxt == NULL)
2726 return;
2727 ctxt->varLookupFunc = (void *) f;
2728 ctxt->varLookupData = data;
2729}
2730
2731/**
2732 * xmlXPathVariableLookup:
2733 * @ctxt: the XPath context
2734 * @name: the variable name
2735 *
2736 * Search in the Variable array of the context for the given
2737 * variable value.
2738 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002739 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002740 */
2741xmlXPathObjectPtr
2742xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2743 if (ctxt == NULL)
2744 return(NULL);
2745
2746 if (ctxt->varLookupFunc != NULL) {
2747 xmlXPathObjectPtr ret;
2748
2749 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2750 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00002751 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002752 }
2753 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
2754}
2755
2756/**
2757 * xmlXPathVariableLookupNS:
2758 * @ctxt: the XPath context
2759 * @name: the variable name
2760 * @ns_uri: the variable namespace URI
2761 *
2762 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00002763 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00002764 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002765 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002766 */
2767xmlXPathObjectPtr
2768xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2769 const xmlChar *ns_uri) {
2770 if (ctxt == NULL)
2771 return(NULL);
2772
2773 if (ctxt->varLookupFunc != NULL) {
2774 xmlXPathObjectPtr ret;
2775
2776 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2777 (ctxt->varLookupData, name, ns_uri);
2778 if (ret != NULL) return(ret);
2779 }
2780
2781 if (ctxt->varHash == NULL)
2782 return(NULL);
2783 if (name == NULL)
2784 return(NULL);
2785
Daniel Veillard8c357d52001-07-03 23:43:33 +00002786 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
2787 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00002788}
2789
2790/**
2791 * xmlXPathRegisteredVariablesCleanup:
2792 * @ctxt: the XPath context
2793 *
2794 * Cleanup the XPath context data associated to registered variables
2795 */
2796void
2797xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
2798 if (ctxt == NULL)
2799 return;
2800
Daniel Veillard76d66f42001-05-16 21:05:17 +00002801 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00002802 ctxt->varHash = NULL;
2803}
2804
2805/**
2806 * xmlXPathRegisterNs:
2807 * @ctxt: the XPath context
2808 * @prefix: the namespace prefix
2809 * @ns_uri: the namespace name
2810 *
2811 * Register a new namespace. If @ns_uri is NULL it unregisters
2812 * the namespace
2813 *
2814 * Returns 0 in case of success, -1 in case of error
2815 */
2816int
2817xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
2818 const xmlChar *ns_uri) {
2819 if (ctxt == NULL)
2820 return(-1);
2821 if (prefix == NULL)
2822 return(-1);
2823
2824 if (ctxt->nsHash == NULL)
2825 ctxt->nsHash = xmlHashCreate(10);
2826 if (ctxt->nsHash == NULL)
2827 return(-1);
2828 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) ns_uri,
2829 (xmlHashDeallocator)xmlFree));
2830}
2831
2832/**
2833 * xmlXPathNsLookup:
2834 * @ctxt: the XPath context
2835 * @prefix: the namespace prefix value
2836 *
2837 * Search in the namespace declaration array of the context for the given
2838 * namespace name associated to the given prefix
2839 *
2840 * Returns the value or NULL if not found
2841 */
2842const xmlChar *
2843xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
2844 if (ctxt == NULL)
2845 return(NULL);
2846 if (prefix == NULL)
2847 return(NULL);
2848
2849#ifdef XML_XML_NAMESPACE
2850 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
2851 return(XML_XML_NAMESPACE);
2852#endif
2853
Daniel Veillardc8f620b2001-04-30 20:31:33 +00002854 if (ctxt->namespaces != NULL) {
2855 int i;
2856
2857 for (i = 0;i < ctxt->nsNr;i++) {
2858 if ((ctxt->namespaces[i] != NULL) &&
2859 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
2860 return(ctxt->namespaces[i]->href);
2861 }
2862 }
Owen Taylor3473f882001-02-23 17:55:21 +00002863
2864 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
2865}
2866
2867/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002868 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00002869 * @ctxt: the XPath context
2870 *
2871 * Cleanup the XPath context data associated to registered variables
2872 */
2873void
2874xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
2875 if (ctxt == NULL)
2876 return;
2877
2878 xmlHashFree(ctxt->nsHash, NULL);
2879 ctxt->nsHash = NULL;
2880}
2881
2882/************************************************************************
2883 * *
2884 * Routines to handle Values *
2885 * *
2886 ************************************************************************/
2887
2888/* Allocations are terrible, one need to optimize all this !!! */
2889
2890/**
2891 * xmlXPathNewFloat:
2892 * @val: the double value
2893 *
2894 * Create a new xmlXPathObjectPtr of type double and of value @val
2895 *
2896 * Returns the newly created object.
2897 */
2898xmlXPathObjectPtr
2899xmlXPathNewFloat(double val) {
2900 xmlXPathObjectPtr ret;
2901
2902 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2903 if (ret == NULL) {
2904 xmlGenericError(xmlGenericErrorContext,
2905 "xmlXPathNewFloat: out of memory\n");
2906 return(NULL);
2907 }
2908 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2909 ret->type = XPATH_NUMBER;
2910 ret->floatval = val;
2911 return(ret);
2912}
2913
2914/**
2915 * xmlXPathNewBoolean:
2916 * @val: the boolean value
2917 *
2918 * Create a new xmlXPathObjectPtr of type boolean and of value @val
2919 *
2920 * Returns the newly created object.
2921 */
2922xmlXPathObjectPtr
2923xmlXPathNewBoolean(int val) {
2924 xmlXPathObjectPtr ret;
2925
2926 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2927 if (ret == NULL) {
2928 xmlGenericError(xmlGenericErrorContext,
2929 "xmlXPathNewBoolean: out of memory\n");
2930 return(NULL);
2931 }
2932 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2933 ret->type = XPATH_BOOLEAN;
2934 ret->boolval = (val != 0);
2935 return(ret);
2936}
2937
2938/**
2939 * xmlXPathNewString:
2940 * @val: the xmlChar * value
2941 *
2942 * Create a new xmlXPathObjectPtr of type string and of value @val
2943 *
2944 * Returns the newly created object.
2945 */
2946xmlXPathObjectPtr
2947xmlXPathNewString(const xmlChar *val) {
2948 xmlXPathObjectPtr ret;
2949
2950 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2951 if (ret == NULL) {
2952 xmlGenericError(xmlGenericErrorContext,
2953 "xmlXPathNewString: out of memory\n");
2954 return(NULL);
2955 }
2956 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2957 ret->type = XPATH_STRING;
2958 if (val != NULL)
2959 ret->stringval = xmlStrdup(val);
2960 else
2961 ret->stringval = xmlStrdup((const xmlChar *)"");
2962 return(ret);
2963}
2964
2965/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002966 * xmlXPathWrapString:
2967 * @val: the xmlChar * value
2968 *
2969 * Wraps the @val string into an XPath object.
2970 *
2971 * Returns the newly created object.
2972 */
2973xmlXPathObjectPtr
2974xmlXPathWrapString (xmlChar *val) {
2975 xmlXPathObjectPtr ret;
2976
2977 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2978 if (ret == NULL) {
2979 xmlGenericError(xmlGenericErrorContext,
2980 "xmlXPathWrapString: out of memory\n");
2981 return(NULL);
2982 }
2983 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2984 ret->type = XPATH_STRING;
2985 ret->stringval = val;
2986 return(ret);
2987}
2988
2989/**
Owen Taylor3473f882001-02-23 17:55:21 +00002990 * xmlXPathNewCString:
2991 * @val: the char * value
2992 *
2993 * Create a new xmlXPathObjectPtr of type string and of value @val
2994 *
2995 * Returns the newly created object.
2996 */
2997xmlXPathObjectPtr
2998xmlXPathNewCString(const char *val) {
2999 xmlXPathObjectPtr ret;
3000
3001 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3002 if (ret == NULL) {
3003 xmlGenericError(xmlGenericErrorContext,
3004 "xmlXPathNewCString: out of memory\n");
3005 return(NULL);
3006 }
3007 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3008 ret->type = XPATH_STRING;
3009 ret->stringval = xmlStrdup(BAD_CAST val);
3010 return(ret);
3011}
3012
3013/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003014 * xmlXPathWrapCString:
3015 * @val: the char * value
3016 *
3017 * Wraps a string into an XPath object.
3018 *
3019 * Returns the newly created object.
3020 */
3021xmlXPathObjectPtr
3022xmlXPathWrapCString (char * val) {
3023 return(xmlXPathWrapString((xmlChar *)(val)));
3024}
3025
3026/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003027 * xmlXPathWrapExternal:
3028 * @val: the user data
3029 *
3030 * Wraps the @val data into an XPath object.
3031 *
3032 * Returns the newly created object.
3033 */
3034xmlXPathObjectPtr
3035xmlXPathWrapExternal (void *val) {
3036 xmlXPathObjectPtr ret;
3037
3038 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3039 if (ret == NULL) {
3040 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003041 "xmlXPathWrapExternal: out of memory\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003042 return(NULL);
3043 }
3044 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3045 ret->type = XPATH_USERS;
3046 ret->user = val;
3047 return(ret);
3048}
3049
3050/**
Owen Taylor3473f882001-02-23 17:55:21 +00003051 * xmlXPathObjectCopy:
3052 * @val: the original object
3053 *
3054 * allocate a new copy of a given object
3055 *
3056 * Returns the newly created object.
3057 */
3058xmlXPathObjectPtr
3059xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3060 xmlXPathObjectPtr ret;
3061
3062 if (val == NULL)
3063 return(NULL);
3064
3065 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3066 if (ret == NULL) {
3067 xmlGenericError(xmlGenericErrorContext,
3068 "xmlXPathObjectCopy: out of memory\n");
3069 return(NULL);
3070 }
3071 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3072 switch (val->type) {
3073 case XPATH_BOOLEAN:
3074 case XPATH_NUMBER:
3075 case XPATH_POINT:
3076 case XPATH_RANGE:
3077 break;
3078 case XPATH_STRING:
3079 ret->stringval = xmlStrdup(val->stringval);
3080 break;
3081 case XPATH_XSLT_TREE:
3082 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003083 (val->nodesetval->nodeTab != NULL)) {
3084 ret->boolval = 1;
Daniel Veillard6ab38382001-10-06 13:08:27 +00003085 ret->user = xmlDocCopyNode(val->nodesetval->nodeTab[0],
3086 val->nodesetval->nodeTab[0]->doc, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003087 ret->nodesetval = xmlXPathNodeSetCreate(
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003088 (xmlNodePtr) ret->user);
3089 } else
Owen Taylor3473f882001-02-23 17:55:21 +00003090 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003091 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00003092 break;
3093 case XPATH_NODESET:
3094 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003095 /* Do not deallocate the copied tree value */
3096 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003097 break;
3098 case XPATH_LOCATIONSET:
3099#ifdef LIBXML_XPTR_ENABLED
3100 {
3101 xmlLocationSetPtr loc = val->user;
3102 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3103 break;
3104 }
3105#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00003106 case XPATH_USERS:
3107 ret->user = val->user;
3108 break;
3109 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00003110 xmlGenericError(xmlGenericErrorContext,
3111 "xmlXPathObjectCopy: unsupported type %d\n",
3112 val->type);
3113 break;
3114 }
3115 return(ret);
3116}
3117
3118/**
3119 * xmlXPathFreeObject:
3120 * @obj: the object to free
3121 *
3122 * Free up an xmlXPathObjectPtr object.
3123 */
3124void
3125xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3126 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003127 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00003128 if (obj->boolval) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003129 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003130 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00003131 xmlFreeNodeList((xmlNodePtr) obj->user);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003132 } else if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00003133 xmlXPathFreeValueTree(obj->nodesetval);
3134 } else {
3135 if (obj->nodesetval != NULL)
3136 xmlXPathFreeNodeSet(obj->nodesetval);
3137 }
Owen Taylor3473f882001-02-23 17:55:21 +00003138#ifdef LIBXML_XPTR_ENABLED
3139 } else if (obj->type == XPATH_LOCATIONSET) {
3140 if (obj->user != NULL)
3141 xmlXPtrFreeLocationSet(obj->user);
3142#endif
3143 } else if (obj->type == XPATH_STRING) {
3144 if (obj->stringval != NULL)
3145 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00003146 }
3147
Owen Taylor3473f882001-02-23 17:55:21 +00003148 xmlFree(obj);
3149}
3150
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003151
3152/************************************************************************
3153 * *
3154 * Type Casting Routines *
3155 * *
3156 ************************************************************************/
3157
3158/**
3159 * xmlXPathCastBooleanToString:
3160 * @val: a boolean
3161 *
3162 * Converts a boolean to its string value.
3163 *
3164 * Returns a newly allocated string.
3165 */
3166xmlChar *
3167xmlXPathCastBooleanToString (int val) {
3168 xmlChar *ret;
3169 if (val)
3170 ret = xmlStrdup((const xmlChar *) "true");
3171 else
3172 ret = xmlStrdup((const xmlChar *) "false");
3173 return(ret);
3174}
3175
3176/**
3177 * xmlXPathCastNumberToString:
3178 * @val: a number
3179 *
3180 * Converts a number to its string value.
3181 *
3182 * Returns a newly allocated string.
3183 */
3184xmlChar *
3185xmlXPathCastNumberToString (double val) {
3186 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00003187 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003188 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003189 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003190 break;
3191 case -1:
3192 ret = xmlStrdup((const xmlChar *) "-Infinity");
3193 break;
3194 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003195 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003196 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00003197 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
3198 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003199 } else {
3200 /* could be improved */
3201 char buf[100];
3202 xmlXPathFormatNumber(val, buf, 100);
3203 ret = xmlStrdup((const xmlChar *) buf);
3204 }
3205 }
3206 return(ret);
3207}
3208
3209/**
3210 * xmlXPathCastNodeToString:
3211 * @node: a node
3212 *
3213 * Converts a node to its string value.
3214 *
3215 * Returns a newly allocated string.
3216 */
3217xmlChar *
3218xmlXPathCastNodeToString (xmlNodePtr node) {
3219 return(xmlNodeGetContent(node));
3220}
3221
3222/**
3223 * xmlXPathCastNodeSetToString:
3224 * @ns: a node-set
3225 *
3226 * Converts a node-set to its string value.
3227 *
3228 * Returns a newly allocated string.
3229 */
3230xmlChar *
3231xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3232 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3233 return(xmlStrdup((const xmlChar *) ""));
3234
3235 xmlXPathNodeSetSort(ns);
3236 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3237}
3238
3239/**
3240 * xmlXPathCastToString:
3241 * @val: an XPath object
3242 *
3243 * Converts an existing object to its string() equivalent
3244 *
3245 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003246 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003247 * string object).
3248 */
3249xmlChar *
3250xmlXPathCastToString(xmlXPathObjectPtr val) {
3251 xmlChar *ret = NULL;
3252
3253 if (val == NULL)
3254 return(xmlStrdup((const xmlChar *) ""));
3255 switch (val->type) {
3256 case XPATH_UNDEFINED:
3257#ifdef DEBUG_EXPR
3258 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3259#endif
3260 ret = xmlStrdup((const xmlChar *) "");
3261 break;
3262 case XPATH_XSLT_TREE:
3263 case XPATH_NODESET:
3264 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3265 break;
3266 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00003267 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003268 case XPATH_BOOLEAN:
3269 ret = xmlXPathCastBooleanToString(val->boolval);
3270 break;
3271 case XPATH_NUMBER: {
3272 ret = xmlXPathCastNumberToString(val->floatval);
3273 break;
3274 }
3275 case XPATH_USERS:
3276 case XPATH_POINT:
3277 case XPATH_RANGE:
3278 case XPATH_LOCATIONSET:
3279 TODO
3280 ret = xmlStrdup((const xmlChar *) "");
3281 break;
3282 }
3283 return(ret);
3284}
3285
3286/**
3287 * xmlXPathConvertString:
3288 * @val: an XPath object
3289 *
3290 * Converts an existing object to its string() equivalent
3291 *
3292 * Returns the new object, the old one is freed (or the operation
3293 * is done directly on @val)
3294 */
3295xmlXPathObjectPtr
3296xmlXPathConvertString(xmlXPathObjectPtr val) {
3297 xmlChar *res = NULL;
3298
3299 if (val == NULL)
3300 return(xmlXPathNewCString(""));
3301
3302 switch (val->type) {
3303 case XPATH_UNDEFINED:
3304#ifdef DEBUG_EXPR
3305 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3306#endif
3307 break;
3308 case XPATH_XSLT_TREE:
3309 case XPATH_NODESET:
3310 res = xmlXPathCastNodeSetToString(val->nodesetval);
3311 break;
3312 case XPATH_STRING:
3313 return(val);
3314 case XPATH_BOOLEAN:
3315 res = xmlXPathCastBooleanToString(val->boolval);
3316 break;
3317 case XPATH_NUMBER:
3318 res = xmlXPathCastNumberToString(val->floatval);
3319 break;
3320 case XPATH_USERS:
3321 case XPATH_POINT:
3322 case XPATH_RANGE:
3323 case XPATH_LOCATIONSET:
3324 TODO;
3325 break;
3326 }
3327 xmlXPathFreeObject(val);
3328 if (res == NULL)
3329 return(xmlXPathNewCString(""));
3330 return(xmlXPathWrapString(res));
3331}
3332
3333/**
3334 * xmlXPathCastBooleanToNumber:
3335 * @val: a boolean
3336 *
3337 * Converts a boolean to its number value
3338 *
3339 * Returns the number value
3340 */
3341double
3342xmlXPathCastBooleanToNumber(int val) {
3343 if (val)
3344 return(1.0);
3345 return(0.0);
3346}
3347
3348/**
3349 * xmlXPathCastStringToNumber:
3350 * @val: a string
3351 *
3352 * Converts a string to its number value
3353 *
3354 * Returns the number value
3355 */
3356double
3357xmlXPathCastStringToNumber(const xmlChar * val) {
3358 return(xmlXPathStringEvalNumber(val));
3359}
3360
3361/**
3362 * xmlXPathCastNodeToNumber:
3363 * @node: a node
3364 *
3365 * Converts a node to its number value
3366 *
3367 * Returns the number value
3368 */
3369double
3370xmlXPathCastNodeToNumber (xmlNodePtr node) {
3371 xmlChar *strval;
3372 double ret;
3373
3374 if (node == NULL)
3375 return(xmlXPathNAN);
3376 strval = xmlXPathCastNodeToString(node);
3377 if (strval == NULL)
3378 return(xmlXPathNAN);
3379 ret = xmlXPathCastStringToNumber(strval);
3380 xmlFree(strval);
3381
3382 return(ret);
3383}
3384
3385/**
3386 * xmlXPathCastNodeSetToNumber:
3387 * @ns: a node-set
3388 *
3389 * Converts a node-set to its number value
3390 *
3391 * Returns the number value
3392 */
3393double
3394xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3395 xmlChar *str;
3396 double ret;
3397
3398 if (ns == NULL)
3399 return(xmlXPathNAN);
3400 str = xmlXPathCastNodeSetToString(ns);
3401 ret = xmlXPathCastStringToNumber(str);
3402 xmlFree(str);
3403 return(ret);
3404}
3405
3406/**
3407 * xmlXPathCastToNumber:
3408 * @val: an XPath object
3409 *
3410 * Converts an XPath object to its number value
3411 *
3412 * Returns the number value
3413 */
3414double
3415xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3416 double ret = 0.0;
3417
3418 if (val == NULL)
3419 return(xmlXPathNAN);
3420 switch (val->type) {
3421 case XPATH_UNDEFINED:
3422#ifdef DEGUB_EXPR
3423 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3424#endif
3425 ret = xmlXPathNAN;
3426 break;
3427 case XPATH_XSLT_TREE:
3428 case XPATH_NODESET:
3429 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3430 break;
3431 case XPATH_STRING:
3432 ret = xmlXPathCastStringToNumber(val->stringval);
3433 break;
3434 case XPATH_NUMBER:
3435 ret = val->floatval;
3436 break;
3437 case XPATH_BOOLEAN:
3438 ret = xmlXPathCastBooleanToNumber(val->boolval);
3439 break;
3440 case XPATH_USERS:
3441 case XPATH_POINT:
3442 case XPATH_RANGE:
3443 case XPATH_LOCATIONSET:
3444 TODO;
3445 ret = xmlXPathNAN;
3446 break;
3447 }
3448 return(ret);
3449}
3450
3451/**
3452 * xmlXPathConvertNumber:
3453 * @val: an XPath object
3454 *
3455 * Converts an existing object to its number() equivalent
3456 *
3457 * Returns the new object, the old one is freed (or the operation
3458 * is done directly on @val)
3459 */
3460xmlXPathObjectPtr
3461xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3462 xmlXPathObjectPtr ret;
3463
3464 if (val == NULL)
3465 return(xmlXPathNewFloat(0.0));
3466 if (val->type == XPATH_NUMBER)
3467 return(val);
3468 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3469 xmlXPathFreeObject(val);
3470 return(ret);
3471}
3472
3473/**
3474 * xmlXPathCastNumberToBoolean:
3475 * @val: a number
3476 *
3477 * Converts a number to its boolean value
3478 *
3479 * Returns the boolean value
3480 */
3481int
3482xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003483 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003484 return(0);
3485 return(1);
3486}
3487
3488/**
3489 * xmlXPathCastStringToBoolean:
3490 * @val: a string
3491 *
3492 * Converts a string to its boolean value
3493 *
3494 * Returns the boolean value
3495 */
3496int
3497xmlXPathCastStringToBoolean (const xmlChar *val) {
3498 if ((val == NULL) || (xmlStrlen(val) == 0))
3499 return(0);
3500 return(1);
3501}
3502
3503/**
3504 * xmlXPathCastNodeSetToBoolean:
3505 * @ns: a node-set
3506 *
3507 * Converts a node-set to its boolean value
3508 *
3509 * Returns the boolean value
3510 */
3511int
3512xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3513 if ((ns == NULL) || (ns->nodeNr == 0))
3514 return(0);
3515 return(1);
3516}
3517
3518/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003519 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003520 * @val: an XPath object
3521 *
3522 * Converts an XPath object to its boolean value
3523 *
3524 * Returns the boolean value
3525 */
3526int
3527xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3528 int ret = 0;
3529
3530 if (val == NULL)
3531 return(0);
3532 switch (val->type) {
3533 case XPATH_UNDEFINED:
3534#ifdef DEBUG_EXPR
3535 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3536#endif
3537 ret = 0;
3538 break;
3539 case XPATH_XSLT_TREE:
3540 case XPATH_NODESET:
3541 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3542 break;
3543 case XPATH_STRING:
3544 ret = xmlXPathCastStringToBoolean(val->stringval);
3545 break;
3546 case XPATH_NUMBER:
3547 ret = xmlXPathCastNumberToBoolean(val->floatval);
3548 break;
3549 case XPATH_BOOLEAN:
3550 ret = val->boolval;
3551 break;
3552 case XPATH_USERS:
3553 case XPATH_POINT:
3554 case XPATH_RANGE:
3555 case XPATH_LOCATIONSET:
3556 TODO;
3557 ret = 0;
3558 break;
3559 }
3560 return(ret);
3561}
3562
3563
3564/**
3565 * xmlXPathConvertBoolean:
3566 * @val: an XPath object
3567 *
3568 * Converts an existing object to its boolean() equivalent
3569 *
3570 * Returns the new object, the old one is freed (or the operation
3571 * is done directly on @val)
3572 */
3573xmlXPathObjectPtr
3574xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3575 xmlXPathObjectPtr ret;
3576
3577 if (val == NULL)
3578 return(xmlXPathNewBoolean(0));
3579 if (val->type == XPATH_BOOLEAN)
3580 return(val);
3581 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3582 xmlXPathFreeObject(val);
3583 return(ret);
3584}
3585
Owen Taylor3473f882001-02-23 17:55:21 +00003586/************************************************************************
3587 * *
3588 * Routines to handle XPath contexts *
3589 * *
3590 ************************************************************************/
3591
3592/**
3593 * xmlXPathNewContext:
3594 * @doc: the XML document
3595 *
3596 * Create a new xmlXPathContext
3597 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00003598 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00003599 */
3600xmlXPathContextPtr
3601xmlXPathNewContext(xmlDocPtr doc) {
3602 xmlXPathContextPtr ret;
3603
3604 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3605 if (ret == NULL) {
3606 xmlGenericError(xmlGenericErrorContext,
3607 "xmlXPathNewContext: out of memory\n");
3608 return(NULL);
3609 }
3610 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3611 ret->doc = doc;
3612 ret->node = NULL;
3613
3614 ret->varHash = NULL;
3615
3616 ret->nb_types = 0;
3617 ret->max_types = 0;
3618 ret->types = NULL;
3619
3620 ret->funcHash = xmlHashCreate(0);
3621
3622 ret->nb_axis = 0;
3623 ret->max_axis = 0;
3624 ret->axis = NULL;
3625
3626 ret->nsHash = NULL;
3627 ret->user = NULL;
3628
3629 ret->contextSize = -1;
3630 ret->proximityPosition = -1;
3631
3632 xmlXPathRegisterAllFunctions(ret);
3633
3634 return(ret);
3635}
3636
3637/**
3638 * xmlXPathFreeContext:
3639 * @ctxt: the context to free
3640 *
3641 * Free up an xmlXPathContext
3642 */
3643void
3644xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3645 xmlXPathRegisteredNsCleanup(ctxt);
3646 xmlXPathRegisteredFuncsCleanup(ctxt);
3647 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003648 xmlFree(ctxt);
3649}
3650
3651/************************************************************************
3652 * *
3653 * Routines to handle XPath parser contexts *
3654 * *
3655 ************************************************************************/
3656
3657#define CHECK_CTXT(ctxt) \
3658 if (ctxt == NULL) { \
3659 xmlGenericError(xmlGenericErrorContext, \
3660 "%s:%d Internal error: ctxt == NULL\n", \
3661 __FILE__, __LINE__); \
3662 } \
3663
3664
3665#define CHECK_CONTEXT(ctxt) \
3666 if (ctxt == NULL) { \
3667 xmlGenericError(xmlGenericErrorContext, \
3668 "%s:%d Internal error: no context\n", \
3669 __FILE__, __LINE__); \
3670 } \
3671 else if (ctxt->doc == NULL) { \
3672 xmlGenericError(xmlGenericErrorContext, \
3673 "%s:%d Internal error: no document\n", \
3674 __FILE__, __LINE__); \
3675 } \
3676 else if (ctxt->doc->children == NULL) { \
3677 xmlGenericError(xmlGenericErrorContext, \
3678 "%s:%d Internal error: document without root\n", \
3679 __FILE__, __LINE__); \
3680 } \
3681
3682
3683/**
3684 * xmlXPathNewParserContext:
3685 * @str: the XPath expression
3686 * @ctxt: the XPath context
3687 *
3688 * Create a new xmlXPathParserContext
3689 *
3690 * Returns the xmlXPathParserContext just allocated.
3691 */
3692xmlXPathParserContextPtr
3693xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3694 xmlXPathParserContextPtr ret;
3695
3696 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3697 if (ret == NULL) {
3698 xmlGenericError(xmlGenericErrorContext,
3699 "xmlXPathNewParserContext: out of memory\n");
3700 return(NULL);
3701 }
3702 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3703 ret->cur = ret->base = str;
3704 ret->context = ctxt;
3705
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003706 ret->comp = xmlXPathNewCompExpr();
3707 if (ret->comp == NULL) {
3708 xmlFree(ret->valueTab);
3709 xmlFree(ret);
3710 return(NULL);
3711 }
3712
3713 return(ret);
3714}
3715
3716/**
3717 * xmlXPathCompParserContext:
3718 * @comp: the XPath compiled expression
3719 * @ctxt: the XPath context
3720 *
3721 * Create a new xmlXPathParserContext when processing a compiled expression
3722 *
3723 * Returns the xmlXPathParserContext just allocated.
3724 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003725static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003726xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3727 xmlXPathParserContextPtr ret;
3728
3729 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3730 if (ret == NULL) {
3731 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003732 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003733 return(NULL);
3734 }
3735 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3736
Owen Taylor3473f882001-02-23 17:55:21 +00003737 /* Allocate the value stack */
3738 ret->valueTab = (xmlXPathObjectPtr *)
3739 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003740 if (ret->valueTab == NULL) {
3741 xmlFree(ret);
3742 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003743 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003744 return(NULL);
3745 }
Owen Taylor3473f882001-02-23 17:55:21 +00003746 ret->valueNr = 0;
3747 ret->valueMax = 10;
3748 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003749
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00003750 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003751 ret->comp = comp;
3752
Owen Taylor3473f882001-02-23 17:55:21 +00003753 return(ret);
3754}
3755
3756/**
3757 * xmlXPathFreeParserContext:
3758 * @ctxt: the context to free
3759 *
3760 * Free up an xmlXPathParserContext
3761 */
3762void
3763xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
3764 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003765 xmlFree(ctxt->valueTab);
3766 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003767 if (ctxt->comp)
3768 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00003769 xmlFree(ctxt);
3770}
3771
3772/************************************************************************
3773 * *
3774 * The implicit core function library *
3775 * *
3776 ************************************************************************/
3777
Owen Taylor3473f882001-02-23 17:55:21 +00003778/**
Daniel Veillardf06307e2001-07-03 10:35:50 +00003779 * xmlXPathNodeStringHash:
3780 * @node: a node pointer
3781 *
3782 * Function computing the beginning of the string value of the node,
3783 * used to speed up comparisons
3784 *
3785 * Returns an int usable as a hash
3786 */
3787static unsigned int
3788xmlXPathNodeValHash(xmlNodePtr node) {
3789 int len = 2;
3790 const xmlChar * string = NULL;
3791 xmlNodePtr tmp = NULL;
3792 unsigned int ret = 0;
3793
3794 if (node == NULL)
3795 return(0);
3796
3797
3798 switch (node->type) {
3799 case XML_COMMENT_NODE:
3800 case XML_PI_NODE:
3801 case XML_CDATA_SECTION_NODE:
3802 case XML_TEXT_NODE:
3803 string = node->content;
3804 if (string == NULL)
3805 return(0);
3806 if (string[0] == 0)
3807 return(0);
3808 return(((unsigned int) string[0]) +
3809 (((unsigned int) string[1]) << 8));
3810 case XML_NAMESPACE_DECL:
3811 string = ((xmlNsPtr)node)->href;
3812 if (string == NULL)
3813 return(0);
3814 if (string[0] == 0)
3815 return(0);
3816 return(((unsigned int) string[0]) +
3817 (((unsigned int) string[1]) << 8));
3818 case XML_ATTRIBUTE_NODE:
3819 tmp = ((xmlAttrPtr) node)->children;
3820 break;
3821 case XML_ELEMENT_NODE:
3822 tmp = node->children;
3823 break;
3824 default:
3825 return(0);
3826 }
3827 while (tmp != NULL) {
3828 switch (tmp->type) {
3829 case XML_COMMENT_NODE:
3830 case XML_PI_NODE:
3831 case XML_CDATA_SECTION_NODE:
3832 case XML_TEXT_NODE:
3833 string = tmp->content;
3834 break;
3835 case XML_NAMESPACE_DECL:
3836 string = ((xmlNsPtr)tmp)->href;
3837 break;
3838 default:
3839 break;
3840 }
3841 if ((string != NULL) && (string[0] != 0)) {
3842 if (string[0] == 0)
3843 return(0);
3844 if (len == 1) {
3845 return(ret + (((unsigned int) string[0]) << 8));
3846 }
3847 if (string[1] == 0) {
3848 len = 1;
3849 ret = (unsigned int) string[0];
3850 } else {
3851 return(((unsigned int) string[0]) +
3852 (((unsigned int) string[1]) << 8));
3853 }
3854 }
3855 /*
3856 * Skip to next node
3857 */
3858 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
3859 if (tmp->children->type != XML_ENTITY_DECL) {
3860 tmp = tmp->children;
3861 continue;
3862 }
3863 }
3864 if (tmp == node)
3865 break;
3866
3867 if (tmp->next != NULL) {
3868 tmp = tmp->next;
3869 continue;
3870 }
3871
3872 do {
3873 tmp = tmp->parent;
3874 if (tmp == NULL)
3875 break;
3876 if (tmp == node) {
3877 tmp = NULL;
3878 break;
3879 }
3880 if (tmp->next != NULL) {
3881 tmp = tmp->next;
3882 break;
3883 }
3884 } while (tmp != NULL);
3885 }
3886 return(ret);
3887}
3888
3889/**
3890 * xmlXPathStringHash:
3891 * @string: a string
3892 *
3893 * Function computing the beginning of the string value of the node,
3894 * used to speed up comparisons
3895 *
3896 * Returns an int usable as a hash
3897 */
3898static unsigned int
3899xmlXPathStringHash(const xmlChar * string) {
3900 if (string == NULL)
3901 return((unsigned int) 0);
3902 if (string[0] == 0)
3903 return(0);
3904 return(((unsigned int) string[0]) +
3905 (((unsigned int) string[1]) << 8));
3906}
3907
3908/**
Owen Taylor3473f882001-02-23 17:55:21 +00003909 * xmlXPathCompareNodeSetFloat:
3910 * @ctxt: the XPath Parser context
3911 * @inf: less than (1) or greater than (0)
3912 * @strict: is the comparison strict
3913 * @arg: the node set
3914 * @f: the value
3915 *
3916 * Implement the compare operation between a nodeset and a number
3917 * @ns < @val (1, 1, ...
3918 * @ns <= @val (1, 0, ...
3919 * @ns > @val (0, 1, ...
3920 * @ns >= @val (0, 0, ...
3921 *
3922 * If one object to be compared is a node-set and the other is a number,
3923 * then the comparison will be true if and only if there is a node in the
3924 * node-set such that the result of performing the comparison on the number
3925 * to be compared and on the result of converting the string-value of that
3926 * node to a number using the number function is true.
3927 *
3928 * Returns 0 or 1 depending on the results of the test.
3929 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003930static int
Owen Taylor3473f882001-02-23 17:55:21 +00003931xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
3932 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
3933 int i, ret = 0;
3934 xmlNodeSetPtr ns;
3935 xmlChar *str2;
3936
3937 if ((f == NULL) || (arg == NULL) ||
3938 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3939 xmlXPathFreeObject(arg);
3940 xmlXPathFreeObject(f);
3941 return(0);
3942 }
3943 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003944 if (ns != NULL) {
3945 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003946 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003947 if (str2 != NULL) {
3948 valuePush(ctxt,
3949 xmlXPathNewString(str2));
3950 xmlFree(str2);
3951 xmlXPathNumberFunction(ctxt, 1);
3952 valuePush(ctxt, xmlXPathObjectCopy(f));
3953 ret = xmlXPathCompareValues(ctxt, inf, strict);
3954 if (ret)
3955 break;
3956 }
3957 }
Owen Taylor3473f882001-02-23 17:55:21 +00003958 }
3959 xmlXPathFreeObject(arg);
3960 xmlXPathFreeObject(f);
3961 return(ret);
3962}
3963
3964/**
3965 * xmlXPathCompareNodeSetString:
3966 * @ctxt: the XPath Parser context
3967 * @inf: less than (1) or greater than (0)
3968 * @strict: is the comparison strict
3969 * @arg: the node set
3970 * @s: the value
3971 *
3972 * Implement the compare operation between a nodeset and a string
3973 * @ns < @val (1, 1, ...
3974 * @ns <= @val (1, 0, ...
3975 * @ns > @val (0, 1, ...
3976 * @ns >= @val (0, 0, ...
3977 *
3978 * If one object to be compared is a node-set and the other is a string,
3979 * then the comparison will be true if and only if there is a node in
3980 * the node-set such that the result of performing the comparison on the
3981 * string-value of the node and the other string is true.
3982 *
3983 * Returns 0 or 1 depending on the results of the test.
3984 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003985static int
Owen Taylor3473f882001-02-23 17:55:21 +00003986xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
3987 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
3988 int i, ret = 0;
3989 xmlNodeSetPtr ns;
3990 xmlChar *str2;
3991
3992 if ((s == NULL) || (arg == NULL) ||
3993 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3994 xmlXPathFreeObject(arg);
3995 xmlXPathFreeObject(s);
3996 return(0);
3997 }
3998 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003999 if (ns != NULL) {
4000 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004001 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004002 if (str2 != NULL) {
4003 valuePush(ctxt,
4004 xmlXPathNewString(str2));
4005 xmlFree(str2);
4006 valuePush(ctxt, xmlXPathObjectCopy(s));
4007 ret = xmlXPathCompareValues(ctxt, inf, strict);
4008 if (ret)
4009 break;
4010 }
4011 }
Owen Taylor3473f882001-02-23 17:55:21 +00004012 }
4013 xmlXPathFreeObject(arg);
4014 xmlXPathFreeObject(s);
4015 return(ret);
4016}
4017
4018/**
4019 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004020 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00004021 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004022 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00004023 * @arg2: the second node set object
4024 *
4025 * Implement the compare operation on nodesets:
4026 *
4027 * If both objects to be compared are node-sets, then the comparison
4028 * will be true if and only if there is a node in the first node-set
4029 * and a node in the second node-set such that the result of performing
4030 * the comparison on the string-values of the two nodes is true.
4031 * ....
4032 * When neither object to be compared is a node-set and the operator
4033 * is <=, <, >= or >, then the objects are compared by converting both
4034 * objects to numbers and comparing the numbers according to IEEE 754.
4035 * ....
4036 * The number function converts its argument to a number as follows:
4037 * - a string that consists of optional whitespace followed by an
4038 * optional minus sign followed by a Number followed by whitespace
4039 * is converted to the IEEE 754 number that is nearest (according
4040 * to the IEEE 754 round-to-nearest rule) to the mathematical value
4041 * represented by the string; any other string is converted to NaN
4042 *
4043 * Conclusion all nodes need to be converted first to their string value
4044 * and then the comparison must be done when possible
4045 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004046static int
4047xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00004048 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4049 int i, j, init = 0;
4050 double val1;
4051 double *values2;
4052 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004053 xmlNodeSetPtr ns1;
4054 xmlNodeSetPtr ns2;
4055
4056 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004057 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4058 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004059 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004060 }
Owen Taylor3473f882001-02-23 17:55:21 +00004061 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004062 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4063 xmlXPathFreeObject(arg1);
4064 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004065 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004066 }
Owen Taylor3473f882001-02-23 17:55:21 +00004067
4068 ns1 = arg1->nodesetval;
4069 ns2 = arg2->nodesetval;
4070
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004071 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004072 xmlXPathFreeObject(arg1);
4073 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004074 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004075 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004076 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004077 xmlXPathFreeObject(arg1);
4078 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004079 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004080 }
Owen Taylor3473f882001-02-23 17:55:21 +00004081
4082 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4083 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004084 xmlXPathFreeObject(arg1);
4085 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004086 return(0);
4087 }
4088 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004089 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004090 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004091 continue;
4092 for (j = 0;j < ns2->nodeNr;j++) {
4093 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004094 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004095 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004096 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004097 continue;
4098 if (inf && strict)
4099 ret = (val1 < values2[j]);
4100 else if (inf && !strict)
4101 ret = (val1 <= values2[j]);
4102 else if (!inf && strict)
4103 ret = (val1 > values2[j]);
4104 else if (!inf && !strict)
4105 ret = (val1 >= values2[j]);
4106 if (ret)
4107 break;
4108 }
4109 if (ret)
4110 break;
4111 init = 1;
4112 }
4113 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004114 xmlXPathFreeObject(arg1);
4115 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004116 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004117}
4118
4119/**
4120 * xmlXPathCompareNodeSetValue:
4121 * @ctxt: the XPath Parser context
4122 * @inf: less than (1) or greater than (0)
4123 * @strict: is the comparison strict
4124 * @arg: the node set
4125 * @val: the value
4126 *
4127 * Implement the compare operation between a nodeset and a value
4128 * @ns < @val (1, 1, ...
4129 * @ns <= @val (1, 0, ...
4130 * @ns > @val (0, 1, ...
4131 * @ns >= @val (0, 0, ...
4132 *
4133 * If one object to be compared is a node-set and the other is a boolean,
4134 * then the comparison will be true if and only if the result of performing
4135 * the comparison on the boolean and on the result of converting
4136 * the node-set to a boolean using the boolean function is true.
4137 *
4138 * Returns 0 or 1 depending on the results of the test.
4139 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004140static int
Owen Taylor3473f882001-02-23 17:55:21 +00004141xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4142 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4143 if ((val == NULL) || (arg == NULL) ||
4144 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4145 return(0);
4146
4147 switch(val->type) {
4148 case XPATH_NUMBER:
4149 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4150 case XPATH_NODESET:
4151 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004152 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004153 case XPATH_STRING:
4154 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4155 case XPATH_BOOLEAN:
4156 valuePush(ctxt, arg);
4157 xmlXPathBooleanFunction(ctxt, 1);
4158 valuePush(ctxt, val);
4159 return(xmlXPathCompareValues(ctxt, inf, strict));
4160 default:
4161 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004162 }
4163 return(0);
4164}
4165
4166/**
4167 * xmlXPathEqualNodeSetString
4168 * @arg: the nodeset object argument
4169 * @str: the string to compare to.
4170 *
4171 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4172 * If one object to be compared is a node-set and the other is a string,
4173 * then the comparison will be true if and only if there is a node in
4174 * the node-set such that the result of performing the comparison on the
4175 * string-value of the node and the other string is true.
4176 *
4177 * Returns 0 or 1 depending on the results of the test.
4178 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004179static int
Daniel Veillardf06307e2001-07-03 10:35:50 +00004180xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str)
4181{
Owen Taylor3473f882001-02-23 17:55:21 +00004182 int i;
4183 xmlNodeSetPtr ns;
4184 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004185 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004186
4187 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004188 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4189 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004190 ns = arg->nodesetval;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004191 hash = xmlXPathStringHash(str);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004192 if (ns == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004193 return (0);
Daniel Veillard73c9c042001-07-05 20:02:54 +00004194 if (ns->nodeNr <= 0) {
4195 if (hash == 0)
4196 return(1);
4197 return(0);
4198 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004199 for (i = 0; i < ns->nodeNr; i++) {
4200 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4201 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4202 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4203 xmlFree(str2);
4204 return (1);
4205 }
4206 if (str2 != NULL)
4207 xmlFree(str2);
4208 }
Owen Taylor3473f882001-02-23 17:55:21 +00004209 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004210 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004211}
4212
4213/**
4214 * xmlXPathEqualNodeSetFloat
4215 * @arg: the nodeset object argument
4216 * @f: the float to compare to
4217 *
4218 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4219 * If one object to be compared is a node-set and the other is a number,
4220 * then the comparison will be true if and only if there is a node in
4221 * the node-set such that the result of performing the comparison on the
4222 * number to be compared and on the result of converting the string-value
4223 * of that node to a number using the number function is true.
4224 *
4225 * Returns 0 or 1 depending on the results of the test.
4226 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004227static int
Owen Taylor3473f882001-02-23 17:55:21 +00004228xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, double f) {
4229 char buf[100] = "";
4230
4231 if ((arg == NULL) ||
4232 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4233 return(0);
4234
Bjorn Reesee1dc0112001-03-03 12:09:03 +00004235 xmlXPathFormatNumber(f, buf, sizeof(buf));
Owen Taylor3473f882001-02-23 17:55:21 +00004236 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
4237}
4238
4239
4240/**
4241 * xmlXPathEqualNodeSets
4242 * @arg1: first nodeset object argument
4243 * @arg2: second nodeset object argument
4244 *
4245 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
4246 * If both objects to be compared are node-sets, then the comparison
4247 * will be true if and only if there is a node in the first node-set and
4248 * a node in the second node-set such that the result of performing the
4249 * comparison on the string-values of the two nodes is true.
4250 *
4251 * (needless to say, this is a costly operation)
4252 *
4253 * Returns 0 or 1 depending on the results of the test.
4254 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004255static int
Owen Taylor3473f882001-02-23 17:55:21 +00004256xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4257 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004258 unsigned int *hashs1;
4259 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004260 xmlChar **values1;
4261 xmlChar **values2;
4262 int ret = 0;
4263 xmlNodeSetPtr ns1;
4264 xmlNodeSetPtr ns2;
4265
4266 if ((arg1 == NULL) ||
4267 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4268 return(0);
4269 if ((arg2 == NULL) ||
4270 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4271 return(0);
4272
4273 ns1 = arg1->nodesetval;
4274 ns2 = arg2->nodesetval;
4275
Daniel Veillard911f49a2001-04-07 15:39:35 +00004276 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004277 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004278 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004279 return(0);
4280
4281 /*
4282 * check if there is a node pertaining to both sets
4283 */
4284 for (i = 0;i < ns1->nodeNr;i++)
4285 for (j = 0;j < ns2->nodeNr;j++)
4286 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4287 return(1);
4288
4289 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
4290 if (values1 == NULL)
4291 return(0);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004292 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4293 if (hashs1 == NULL) {
4294 xmlFree(values1);
4295 return(0);
4296 }
Owen Taylor3473f882001-02-23 17:55:21 +00004297 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4298 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4299 if (values2 == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004300 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004301 xmlFree(values1);
4302 return(0);
4303 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004304 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4305 if (hashs2 == NULL) {
4306 xmlFree(hashs1);
4307 xmlFree(values1);
4308 xmlFree(values2);
4309 return(0);
4310 }
Owen Taylor3473f882001-02-23 17:55:21 +00004311 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4312 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004313 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004314 for (j = 0;j < ns2->nodeNr;j++) {
4315 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004316 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
4317 if (hashs1[i] == hashs2[j]) {
4318 if (values1[i] == NULL)
4319 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4320 if (values2[j] == NULL)
4321 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
4322 ret = xmlStrEqual(values1[i], values2[j]);
4323 if (ret)
4324 break;
4325 }
Owen Taylor3473f882001-02-23 17:55:21 +00004326 }
4327 if (ret)
4328 break;
4329 }
4330 for (i = 0;i < ns1->nodeNr;i++)
4331 if (values1[i] != NULL)
4332 xmlFree(values1[i]);
4333 for (j = 0;j < ns2->nodeNr;j++)
4334 if (values2[j] != NULL)
4335 xmlFree(values2[j]);
4336 xmlFree(values1);
4337 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004338 xmlFree(hashs1);
4339 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004340 return(ret);
4341}
4342
4343/**
4344 * xmlXPathEqualValues:
4345 * @ctxt: the XPath Parser context
4346 *
4347 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4348 *
4349 * Returns 0 or 1 depending on the results of the test.
4350 */
4351int
4352xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4353 xmlXPathObjectPtr arg1, arg2;
4354 int ret = 0;
4355
4356 arg1 = valuePop(ctxt);
4357 if (arg1 == NULL)
4358 XP_ERROR0(XPATH_INVALID_OPERAND);
4359
4360 arg2 = valuePop(ctxt);
4361 if (arg2 == NULL) {
4362 xmlXPathFreeObject(arg1);
4363 XP_ERROR0(XPATH_INVALID_OPERAND);
4364 }
4365
4366 if (arg1 == arg2) {
4367#ifdef DEBUG_EXPR
4368 xmlGenericError(xmlGenericErrorContext,
4369 "Equal: by pointer\n");
4370#endif
4371 return(1);
4372 }
4373
4374 switch (arg1->type) {
4375 case XPATH_UNDEFINED:
4376#ifdef DEBUG_EXPR
4377 xmlGenericError(xmlGenericErrorContext,
4378 "Equal: undefined\n");
4379#endif
4380 break;
4381 case XPATH_XSLT_TREE:
4382 case XPATH_NODESET:
4383 switch (arg2->type) {
4384 case XPATH_UNDEFINED:
4385#ifdef DEBUG_EXPR
4386 xmlGenericError(xmlGenericErrorContext,
4387 "Equal: undefined\n");
4388#endif
4389 break;
4390 case XPATH_XSLT_TREE:
4391 case XPATH_NODESET:
4392 ret = xmlXPathEqualNodeSets(arg1, arg2);
4393 break;
4394 case XPATH_BOOLEAN:
4395 if ((arg1->nodesetval == NULL) ||
4396 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4397 else
4398 ret = 1;
4399 ret = (ret == arg2->boolval);
4400 break;
4401 case XPATH_NUMBER:
4402 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
4403 break;
4404 case XPATH_STRING:
4405 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
4406 break;
4407 case XPATH_USERS:
4408 case XPATH_POINT:
4409 case XPATH_RANGE:
4410 case XPATH_LOCATIONSET:
4411 TODO
4412 break;
4413 }
4414 break;
4415 case XPATH_BOOLEAN:
4416 switch (arg2->type) {
4417 case XPATH_UNDEFINED:
4418#ifdef DEBUG_EXPR
4419 xmlGenericError(xmlGenericErrorContext,
4420 "Equal: undefined\n");
4421#endif
4422 break;
4423 case XPATH_NODESET:
4424 case XPATH_XSLT_TREE:
4425 if ((arg2->nodesetval == NULL) ||
4426 (arg2->nodesetval->nodeNr == 0)) ret = 0;
4427 else
4428 ret = 1;
4429 break;
4430 case XPATH_BOOLEAN:
4431#ifdef DEBUG_EXPR
4432 xmlGenericError(xmlGenericErrorContext,
4433 "Equal: %d boolean %d \n",
4434 arg1->boolval, arg2->boolval);
4435#endif
4436 ret = (arg1->boolval == arg2->boolval);
4437 break;
4438 case XPATH_NUMBER:
4439 if (arg2->floatval) ret = 1;
4440 else ret = 0;
4441 ret = (arg1->boolval == ret);
4442 break;
4443 case XPATH_STRING:
4444 if ((arg2->stringval == NULL) ||
4445 (arg2->stringval[0] == 0)) ret = 0;
4446 else
4447 ret = 1;
4448 ret = (arg1->boolval == ret);
4449 break;
4450 case XPATH_USERS:
4451 case XPATH_POINT:
4452 case XPATH_RANGE:
4453 case XPATH_LOCATIONSET:
4454 TODO
4455 break;
4456 }
4457 break;
4458 case XPATH_NUMBER:
4459 switch (arg2->type) {
4460 case XPATH_UNDEFINED:
4461#ifdef DEBUG_EXPR
4462 xmlGenericError(xmlGenericErrorContext,
4463 "Equal: undefined\n");
4464#endif
4465 break;
4466 case XPATH_NODESET:
4467 case XPATH_XSLT_TREE:
4468 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
4469 break;
4470 case XPATH_BOOLEAN:
4471 if (arg1->floatval) ret = 1;
4472 else ret = 0;
4473 ret = (arg2->boolval == ret);
4474 break;
4475 case XPATH_STRING:
4476 valuePush(ctxt, arg2);
4477 xmlXPathNumberFunction(ctxt, 1);
4478 arg2 = valuePop(ctxt);
4479 /* no break on purpose */
4480 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004481 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004482 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4483 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004484 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4485 if (xmlXPathIsInf(arg2->floatval) == 1)
4486 ret = 1;
4487 else
4488 ret = 0;
4489 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4490 if (xmlXPathIsInf(arg2->floatval) == -1)
4491 ret = 1;
4492 else
4493 ret = 0;
4494 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4495 if (xmlXPathIsInf(arg1->floatval) == 1)
4496 ret = 1;
4497 else
4498 ret = 0;
4499 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4500 if (xmlXPathIsInf(arg1->floatval) == -1)
4501 ret = 1;
4502 else
4503 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004504 } else {
4505 ret = (arg1->floatval == arg2->floatval);
4506 }
Owen Taylor3473f882001-02-23 17:55:21 +00004507 break;
4508 case XPATH_USERS:
4509 case XPATH_POINT:
4510 case XPATH_RANGE:
4511 case XPATH_LOCATIONSET:
4512 TODO
4513 break;
4514 }
4515 break;
4516 case XPATH_STRING:
4517 switch (arg2->type) {
4518 case XPATH_UNDEFINED:
4519#ifdef DEBUG_EXPR
4520 xmlGenericError(xmlGenericErrorContext,
4521 "Equal: undefined\n");
4522#endif
4523 break;
4524 case XPATH_NODESET:
4525 case XPATH_XSLT_TREE:
4526 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
4527 break;
4528 case XPATH_BOOLEAN:
4529 if ((arg1->stringval == NULL) ||
4530 (arg1->stringval[0] == 0)) ret = 0;
4531 else
4532 ret = 1;
4533 ret = (arg2->boolval == ret);
4534 break;
4535 case XPATH_STRING:
4536 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4537 break;
4538 case XPATH_NUMBER:
4539 valuePush(ctxt, arg1);
4540 xmlXPathNumberFunction(ctxt, 1);
4541 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004542 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004543 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4544 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004545 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4546 if (xmlXPathIsInf(arg2->floatval) == 1)
4547 ret = 1;
4548 else
4549 ret = 0;
4550 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4551 if (xmlXPathIsInf(arg2->floatval) == -1)
4552 ret = 1;
4553 else
4554 ret = 0;
4555 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4556 if (xmlXPathIsInf(arg1->floatval) == 1)
4557 ret = 1;
4558 else
4559 ret = 0;
4560 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4561 if (xmlXPathIsInf(arg1->floatval) == -1)
4562 ret = 1;
4563 else
4564 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004565 } else {
4566 ret = (arg1->floatval == arg2->floatval);
4567 }
Owen Taylor3473f882001-02-23 17:55:21 +00004568 break;
4569 case XPATH_USERS:
4570 case XPATH_POINT:
4571 case XPATH_RANGE:
4572 case XPATH_LOCATIONSET:
4573 TODO
4574 break;
4575 }
4576 break;
4577 case XPATH_USERS:
4578 case XPATH_POINT:
4579 case XPATH_RANGE:
4580 case XPATH_LOCATIONSET:
4581 TODO
4582 break;
4583 }
4584 xmlXPathFreeObject(arg1);
4585 xmlXPathFreeObject(arg2);
4586 return(ret);
4587}
4588
4589
4590/**
4591 * xmlXPathCompareValues:
4592 * @ctxt: the XPath Parser context
4593 * @inf: less than (1) or greater than (0)
4594 * @strict: is the comparison strict
4595 *
4596 * Implement the compare operation on XPath objects:
4597 * @arg1 < @arg2 (1, 1, ...
4598 * @arg1 <= @arg2 (1, 0, ...
4599 * @arg1 > @arg2 (0, 1, ...
4600 * @arg1 >= @arg2 (0, 0, ...
4601 *
4602 * When neither object to be compared is a node-set and the operator is
4603 * <=, <, >=, >, then the objects are compared by converted both objects
4604 * to numbers and comparing the numbers according to IEEE 754. The <
4605 * comparison will be true if and only if the first number is less than the
4606 * second number. The <= comparison will be true if and only if the first
4607 * number is less than or equal to the second number. The > comparison
4608 * will be true if and only if the first number is greater than the second
4609 * number. The >= comparison will be true if and only if the first number
4610 * is greater than or equal to the second number.
4611 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004612 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00004613 */
4614int
4615xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004616 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004617 xmlXPathObjectPtr arg1, arg2;
4618
4619 arg2 = valuePop(ctxt);
4620 if (arg2 == NULL) {
4621 XP_ERROR0(XPATH_INVALID_OPERAND);
4622 }
4623
4624 arg1 = valuePop(ctxt);
4625 if (arg1 == NULL) {
4626 xmlXPathFreeObject(arg2);
4627 XP_ERROR0(XPATH_INVALID_OPERAND);
4628 }
4629
4630 if ((arg2->type == XPATH_NODESET) || (arg1->type == XPATH_NODESET)) {
4631 if ((arg2->type == XPATH_NODESET) && (arg1->type == XPATH_NODESET)) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004632 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004633 } else {
4634 if (arg1->type == XPATH_NODESET) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004635 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
4636 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004637 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004638 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
4639 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00004640 }
4641 }
4642 return(ret);
4643 }
4644
4645 if (arg1->type != XPATH_NUMBER) {
4646 valuePush(ctxt, arg1);
4647 xmlXPathNumberFunction(ctxt, 1);
4648 arg1 = valuePop(ctxt);
4649 }
4650 if (arg1->type != XPATH_NUMBER) {
4651 xmlXPathFreeObject(arg1);
4652 xmlXPathFreeObject(arg2);
4653 XP_ERROR0(XPATH_INVALID_OPERAND);
4654 }
4655 if (arg2->type != XPATH_NUMBER) {
4656 valuePush(ctxt, arg2);
4657 xmlXPathNumberFunction(ctxt, 1);
4658 arg2 = valuePop(ctxt);
4659 }
4660 if (arg2->type != XPATH_NUMBER) {
4661 xmlXPathFreeObject(arg1);
4662 xmlXPathFreeObject(arg2);
4663 XP_ERROR0(XPATH_INVALID_OPERAND);
4664 }
4665 /*
4666 * Add tests for infinity and nan
4667 * => feedback on 3.4 for Inf and NaN
4668 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004669 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00004670 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004671 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004672 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004673 arg1i=xmlXPathIsInf(arg1->floatval);
4674 arg2i=xmlXPathIsInf(arg2->floatval);
4675 if (inf && strict) {
4676 if ((arg1i == -1 && arg2i != -1) ||
4677 (arg2i == 1 && arg1i != 1)) {
4678 ret = 1;
4679 } else if (arg1i == 0 && arg2i == 0) {
4680 ret = (arg1->floatval < arg2->floatval);
4681 } else {
4682 ret = 0;
4683 }
4684 }
4685 else if (inf && !strict) {
4686 if (arg1i == -1 || arg2i == 1) {
4687 ret = 1;
4688 } else if (arg1i == 0 && arg2i == 0) {
4689 ret = (arg1->floatval <= arg2->floatval);
4690 } else {
4691 ret = 0;
4692 }
4693 }
4694 else if (!inf && strict) {
4695 if ((arg1i == 1 && arg2i != 1) ||
4696 (arg2i == -1 && arg1i != -1)) {
4697 ret = 1;
4698 } else if (arg1i == 0 && arg2i == 0) {
4699 ret = (arg1->floatval > arg2->floatval);
4700 } else {
4701 ret = 0;
4702 }
4703 }
4704 else if (!inf && !strict) {
4705 if (arg1i == 1 || arg2i == -1) {
4706 ret = 1;
4707 } else if (arg1i == 0 && arg2i == 0) {
4708 ret = (arg1->floatval >= arg2->floatval);
4709 } else {
4710 ret = 0;
4711 }
4712 }
Daniel Veillard21458c82002-03-27 16:12:22 +00004713 }
Owen Taylor3473f882001-02-23 17:55:21 +00004714 xmlXPathFreeObject(arg1);
4715 xmlXPathFreeObject(arg2);
4716 return(ret);
4717}
4718
4719/**
4720 * xmlXPathValueFlipSign:
4721 * @ctxt: the XPath Parser context
4722 *
4723 * Implement the unary - operation on an XPath object
4724 * The numeric operators convert their operands to numbers as if
4725 * by calling the number function.
4726 */
4727void
4728xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004729 CAST_TO_NUMBER;
4730 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00004731 if (ctxt->value->floatval == 0) {
4732 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
4733 ctxt->value->floatval = xmlXPathNZERO;
4734 else
4735 ctxt->value->floatval = 0;
4736 }
4737 else
4738 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00004739}
4740
4741/**
4742 * xmlXPathAddValues:
4743 * @ctxt: the XPath Parser context
4744 *
4745 * Implement the add operation on XPath objects:
4746 * The numeric operators convert their operands to numbers as if
4747 * by calling the number function.
4748 */
4749void
4750xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
4751 xmlXPathObjectPtr arg;
4752 double val;
4753
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004754 arg = valuePop(ctxt);
4755 if (arg == NULL)
4756 XP_ERROR(XPATH_INVALID_OPERAND);
4757 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004758 xmlXPathFreeObject(arg);
4759
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004760 CAST_TO_NUMBER;
4761 CHECK_TYPE(XPATH_NUMBER);
4762 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00004763}
4764
4765/**
4766 * xmlXPathSubValues:
4767 * @ctxt: the XPath Parser context
4768 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004769 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00004770 * The numeric operators convert their operands to numbers as if
4771 * by calling the number function.
4772 */
4773void
4774xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
4775 xmlXPathObjectPtr arg;
4776 double val;
4777
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004778 arg = valuePop(ctxt);
4779 if (arg == NULL)
4780 XP_ERROR(XPATH_INVALID_OPERAND);
4781 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004782 xmlXPathFreeObject(arg);
4783
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004784 CAST_TO_NUMBER;
4785 CHECK_TYPE(XPATH_NUMBER);
4786 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004787}
4788
4789/**
4790 * xmlXPathMultValues:
4791 * @ctxt: the XPath Parser context
4792 *
4793 * Implement the multiply operation on XPath objects:
4794 * The numeric operators convert their operands to numbers as if
4795 * by calling the number function.
4796 */
4797void
4798xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
4799 xmlXPathObjectPtr arg;
4800 double val;
4801
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004802 arg = valuePop(ctxt);
4803 if (arg == NULL)
4804 XP_ERROR(XPATH_INVALID_OPERAND);
4805 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004806 xmlXPathFreeObject(arg);
4807
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004808 CAST_TO_NUMBER;
4809 CHECK_TYPE(XPATH_NUMBER);
4810 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004811}
4812
4813/**
4814 * xmlXPathDivValues:
4815 * @ctxt: the XPath Parser context
4816 *
4817 * Implement the div operation on XPath objects @arg1 / @arg2:
4818 * The numeric operators convert their operands to numbers as if
4819 * by calling the number function.
4820 */
4821void
4822xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
4823 xmlXPathObjectPtr arg;
4824 double val;
4825
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004826 arg = valuePop(ctxt);
4827 if (arg == NULL)
4828 XP_ERROR(XPATH_INVALID_OPERAND);
4829 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004830 xmlXPathFreeObject(arg);
4831
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004832 CAST_TO_NUMBER;
4833 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004834 if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00004835 if (ctxt->value->floatval == 0)
4836 ctxt->value->floatval = xmlXPathNAN;
4837 else if (ctxt->value->floatval > 0)
4838 ctxt->value->floatval = xmlXPathNINF;
4839 else if (ctxt->value->floatval < 0)
4840 ctxt->value->floatval = xmlXPathPINF;
4841 }
4842 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00004843 if (ctxt->value->floatval == 0)
4844 ctxt->value->floatval = xmlXPathNAN;
4845 else if (ctxt->value->floatval > 0)
4846 ctxt->value->floatval = xmlXPathPINF;
4847 else if (ctxt->value->floatval < 0)
4848 ctxt->value->floatval = xmlXPathNINF;
4849 } else
4850 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004851}
4852
4853/**
4854 * xmlXPathModValues:
4855 * @ctxt: the XPath Parser context
4856 *
4857 * Implement the mod operation on XPath objects: @arg1 / @arg2
4858 * The numeric operators convert their operands to numbers as if
4859 * by calling the number function.
4860 */
4861void
4862xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
4863 xmlXPathObjectPtr arg;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00004864 double arg1, arg2, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00004865
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004866 arg = valuePop(ctxt);
4867 if (arg == NULL)
4868 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00004869 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004870 xmlXPathFreeObject(arg);
4871
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004872 CAST_TO_NUMBER;
4873 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00004874 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00004875 if (arg2 == 0)
4876 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00004877 else {
4878 tmp=arg1/arg2;
4879 ctxt->value->floatval = arg2 * (tmp - (double)((int)tmp));
4880 }
Owen Taylor3473f882001-02-23 17:55:21 +00004881}
4882
4883/************************************************************************
4884 * *
4885 * The traversal functions *
4886 * *
4887 ************************************************************************/
4888
Owen Taylor3473f882001-02-23 17:55:21 +00004889/*
4890 * A traversal function enumerates nodes along an axis.
4891 * Initially it must be called with NULL, and it indicates
4892 * termination on the axis by returning NULL.
4893 */
4894typedef xmlNodePtr (*xmlXPathTraversalFunction)
4895 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
4896
4897/**
4898 * xmlXPathNextSelf:
4899 * @ctxt: the XPath Parser context
4900 * @cur: the current node in the traversal
4901 *
4902 * Traversal function for the "self" direction
4903 * The self axis contains just the context node itself
4904 *
4905 * Returns the next element following that axis
4906 */
4907xmlNodePtr
4908xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4909 if (cur == NULL)
4910 return(ctxt->context->node);
4911 return(NULL);
4912}
4913
4914/**
4915 * xmlXPathNextChild:
4916 * @ctxt: the XPath Parser context
4917 * @cur: the current node in the traversal
4918 *
4919 * Traversal function for the "child" direction
4920 * The child axis contains the children of the context node in document order.
4921 *
4922 * Returns the next element following that axis
4923 */
4924xmlNodePtr
4925xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4926 if (cur == NULL) {
4927 if (ctxt->context->node == NULL) return(NULL);
4928 switch (ctxt->context->node->type) {
4929 case XML_ELEMENT_NODE:
4930 case XML_TEXT_NODE:
4931 case XML_CDATA_SECTION_NODE:
4932 case XML_ENTITY_REF_NODE:
4933 case XML_ENTITY_NODE:
4934 case XML_PI_NODE:
4935 case XML_COMMENT_NODE:
4936 case XML_NOTATION_NODE:
4937 case XML_DTD_NODE:
4938 return(ctxt->context->node->children);
4939 case XML_DOCUMENT_NODE:
4940 case XML_DOCUMENT_TYPE_NODE:
4941 case XML_DOCUMENT_FRAG_NODE:
4942 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004943#ifdef LIBXML_DOCB_ENABLED
4944 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004945#endif
4946 return(((xmlDocPtr) ctxt->context->node)->children);
4947 case XML_ELEMENT_DECL:
4948 case XML_ATTRIBUTE_DECL:
4949 case XML_ENTITY_DECL:
4950 case XML_ATTRIBUTE_NODE:
4951 case XML_NAMESPACE_DECL:
4952 case XML_XINCLUDE_START:
4953 case XML_XINCLUDE_END:
4954 return(NULL);
4955 }
4956 return(NULL);
4957 }
4958 if ((cur->type == XML_DOCUMENT_NODE) ||
4959 (cur->type == XML_HTML_DOCUMENT_NODE))
4960 return(NULL);
4961 return(cur->next);
4962}
4963
4964/**
4965 * xmlXPathNextDescendant:
4966 * @ctxt: the XPath Parser context
4967 * @cur: the current node in the traversal
4968 *
4969 * Traversal function for the "descendant" direction
4970 * the descendant axis contains the descendants of the context node in document
4971 * order; a descendant is a child or a child of a child and so on.
4972 *
4973 * Returns the next element following that axis
4974 */
4975xmlNodePtr
4976xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4977 if (cur == NULL) {
4978 if (ctxt->context->node == NULL)
4979 return(NULL);
4980 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4981 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4982 return(NULL);
4983
4984 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
4985 return(ctxt->context->doc->children);
4986 return(ctxt->context->node->children);
4987 }
4988
Daniel Veillard567e1b42001-08-01 15:53:47 +00004989 if (cur->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004990 if (cur->children->type != XML_ENTITY_DECL)
Daniel Veillard567e1b42001-08-01 15:53:47 +00004991 return(cur->children);
4992 }
4993
4994 if (cur == ctxt->context->node) return(NULL);
4995
Owen Taylor3473f882001-02-23 17:55:21 +00004996 if (cur->next != NULL) return(cur->next);
4997
4998 do {
4999 cur = cur->parent;
5000 if (cur == NULL) return(NULL);
5001 if (cur == ctxt->context->node) return(NULL);
5002 if (cur->next != NULL) {
5003 cur = cur->next;
5004 return(cur);
5005 }
5006 } while (cur != NULL);
5007 return(cur);
5008}
5009
5010/**
5011 * xmlXPathNextDescendantOrSelf:
5012 * @ctxt: the XPath Parser context
5013 * @cur: the current node in the traversal
5014 *
5015 * Traversal function for the "descendant-or-self" direction
5016 * the descendant-or-self axis contains the context node and the descendants
5017 * of the context node in document order; thus the context node is the first
5018 * node on the axis, and the first child of the context node is the second node
5019 * on the axis
5020 *
5021 * Returns the next element following that axis
5022 */
5023xmlNodePtr
5024xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5025 if (cur == NULL) {
5026 if (ctxt->context->node == NULL)
5027 return(NULL);
5028 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5029 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5030 return(NULL);
5031 return(ctxt->context->node);
5032 }
5033
5034 return(xmlXPathNextDescendant(ctxt, cur));
5035}
5036
5037/**
5038 * xmlXPathNextParent:
5039 * @ctxt: the XPath Parser context
5040 * @cur: the current node in the traversal
5041 *
5042 * Traversal function for the "parent" direction
5043 * The parent axis contains the parent of the context node, if there is one.
5044 *
5045 * Returns the next element following that axis
5046 */
5047xmlNodePtr
5048xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5049 /*
5050 * the parent of an attribute or namespace node is the element
5051 * to which the attribute or namespace node is attached
5052 * Namespace handling !!!
5053 */
5054 if (cur == NULL) {
5055 if (ctxt->context->node == NULL) return(NULL);
5056 switch (ctxt->context->node->type) {
5057 case XML_ELEMENT_NODE:
5058 case XML_TEXT_NODE:
5059 case XML_CDATA_SECTION_NODE:
5060 case XML_ENTITY_REF_NODE:
5061 case XML_ENTITY_NODE:
5062 case XML_PI_NODE:
5063 case XML_COMMENT_NODE:
5064 case XML_NOTATION_NODE:
5065 case XML_DTD_NODE:
5066 case XML_ELEMENT_DECL:
5067 case XML_ATTRIBUTE_DECL:
5068 case XML_XINCLUDE_START:
5069 case XML_XINCLUDE_END:
5070 case XML_ENTITY_DECL:
5071 if (ctxt->context->node->parent == NULL)
5072 return((xmlNodePtr) ctxt->context->doc);
5073 return(ctxt->context->node->parent);
5074 case XML_ATTRIBUTE_NODE: {
5075 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5076
5077 return(att->parent);
5078 }
5079 case XML_DOCUMENT_NODE:
5080 case XML_DOCUMENT_TYPE_NODE:
5081 case XML_DOCUMENT_FRAG_NODE:
5082 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005083#ifdef LIBXML_DOCB_ENABLED
5084 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005085#endif
5086 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005087 case XML_NAMESPACE_DECL: {
5088 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5089
5090 if ((ns->next != NULL) &&
5091 (ns->next->type != XML_NAMESPACE_DECL))
5092 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005093 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005094 }
Owen Taylor3473f882001-02-23 17:55:21 +00005095 }
5096 }
5097 return(NULL);
5098}
5099
5100/**
5101 * xmlXPathNextAncestor:
5102 * @ctxt: the XPath Parser context
5103 * @cur: the current node in the traversal
5104 *
5105 * Traversal function for the "ancestor" direction
5106 * the ancestor axis contains the ancestors of the context node; the ancestors
5107 * of the context node consist of the parent of context node and the parent's
5108 * parent and so on; the nodes are ordered in reverse document order; thus the
5109 * parent is the first node on the axis, and the parent's parent is the second
5110 * node on the axis
5111 *
5112 * Returns the next element following that axis
5113 */
5114xmlNodePtr
5115xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5116 /*
5117 * the parent of an attribute or namespace node is the element
5118 * to which the attribute or namespace node is attached
5119 * !!!!!!!!!!!!!
5120 */
5121 if (cur == NULL) {
5122 if (ctxt->context->node == NULL) return(NULL);
5123 switch (ctxt->context->node->type) {
5124 case XML_ELEMENT_NODE:
5125 case XML_TEXT_NODE:
5126 case XML_CDATA_SECTION_NODE:
5127 case XML_ENTITY_REF_NODE:
5128 case XML_ENTITY_NODE:
5129 case XML_PI_NODE:
5130 case XML_COMMENT_NODE:
5131 case XML_DTD_NODE:
5132 case XML_ELEMENT_DECL:
5133 case XML_ATTRIBUTE_DECL:
5134 case XML_ENTITY_DECL:
5135 case XML_NOTATION_NODE:
5136 case XML_XINCLUDE_START:
5137 case XML_XINCLUDE_END:
5138 if (ctxt->context->node->parent == NULL)
5139 return((xmlNodePtr) ctxt->context->doc);
5140 return(ctxt->context->node->parent);
5141 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005142 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005143
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005144 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005145 }
5146 case XML_DOCUMENT_NODE:
5147 case XML_DOCUMENT_TYPE_NODE:
5148 case XML_DOCUMENT_FRAG_NODE:
5149 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005150#ifdef LIBXML_DOCB_ENABLED
5151 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005152#endif
5153 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005154 case XML_NAMESPACE_DECL: {
5155 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5156
5157 if ((ns->next != NULL) &&
5158 (ns->next->type != XML_NAMESPACE_DECL))
5159 return((xmlNodePtr) ns->next);
5160 /* Bad, how did that namespace ended-up there ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005161 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005162 }
Owen Taylor3473f882001-02-23 17:55:21 +00005163 }
5164 return(NULL);
5165 }
5166 if (cur == ctxt->context->doc->children)
5167 return((xmlNodePtr) ctxt->context->doc);
5168 if (cur == (xmlNodePtr) ctxt->context->doc)
5169 return(NULL);
5170 switch (cur->type) {
5171 case XML_ELEMENT_NODE:
5172 case XML_TEXT_NODE:
5173 case XML_CDATA_SECTION_NODE:
5174 case XML_ENTITY_REF_NODE:
5175 case XML_ENTITY_NODE:
5176 case XML_PI_NODE:
5177 case XML_COMMENT_NODE:
5178 case XML_NOTATION_NODE:
5179 case XML_DTD_NODE:
5180 case XML_ELEMENT_DECL:
5181 case XML_ATTRIBUTE_DECL:
5182 case XML_ENTITY_DECL:
5183 case XML_XINCLUDE_START:
5184 case XML_XINCLUDE_END:
5185 return(cur->parent);
5186 case XML_ATTRIBUTE_NODE: {
5187 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5188
5189 return(att->parent);
5190 }
5191 case XML_DOCUMENT_NODE:
5192 case XML_DOCUMENT_TYPE_NODE:
5193 case XML_DOCUMENT_FRAG_NODE:
5194 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005195#ifdef LIBXML_DOCB_ENABLED
5196 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005197#endif
5198 return(NULL);
5199 case XML_NAMESPACE_DECL:
5200 /*
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005201 * this should not hapen a namespace can't be
5202 * the ancestor of another node
Owen Taylor3473f882001-02-23 17:55:21 +00005203 */
5204 return(NULL);
5205 }
5206 return(NULL);
5207}
5208
5209/**
5210 * xmlXPathNextAncestorOrSelf:
5211 * @ctxt: the XPath Parser context
5212 * @cur: the current node in the traversal
5213 *
5214 * Traversal function for the "ancestor-or-self" direction
5215 * he ancestor-or-self axis contains the context node and ancestors of
5216 * the context node in reverse document order; thus the context node is
5217 * the first node on the axis, and the context node's parent the second;
5218 * parent here is defined the same as with the parent axis.
5219 *
5220 * Returns the next element following that axis
5221 */
5222xmlNodePtr
5223xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5224 if (cur == NULL)
5225 return(ctxt->context->node);
5226 return(xmlXPathNextAncestor(ctxt, cur));
5227}
5228
5229/**
5230 * xmlXPathNextFollowingSibling:
5231 * @ctxt: the XPath Parser context
5232 * @cur: the current node in the traversal
5233 *
5234 * Traversal function for the "following-sibling" direction
5235 * The following-sibling axis contains the following siblings of the context
5236 * node in document order.
5237 *
5238 * Returns the next element following that axis
5239 */
5240xmlNodePtr
5241xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5242 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5243 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5244 return(NULL);
5245 if (cur == (xmlNodePtr) ctxt->context->doc)
5246 return(NULL);
5247 if (cur == NULL)
5248 return(ctxt->context->node->next);
5249 return(cur->next);
5250}
5251
5252/**
5253 * xmlXPathNextPrecedingSibling:
5254 * @ctxt: the XPath Parser context
5255 * @cur: the current node in the traversal
5256 *
5257 * Traversal function for the "preceding-sibling" direction
5258 * The preceding-sibling axis contains the preceding siblings of the context
5259 * node in reverse document order; the first preceding sibling is first on the
5260 * axis; the sibling preceding that node is the second on the axis and so on.
5261 *
5262 * Returns the next element following that axis
5263 */
5264xmlNodePtr
5265xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5266 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5267 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5268 return(NULL);
5269 if (cur == (xmlNodePtr) ctxt->context->doc)
5270 return(NULL);
5271 if (cur == NULL)
5272 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005273 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5274 cur = cur->prev;
5275 if (cur == NULL)
5276 return(ctxt->context->node->prev);
5277 }
Owen Taylor3473f882001-02-23 17:55:21 +00005278 return(cur->prev);
5279}
5280
5281/**
5282 * xmlXPathNextFollowing:
5283 * @ctxt: the XPath Parser context
5284 * @cur: the current node in the traversal
5285 *
5286 * Traversal function for the "following" direction
5287 * The following axis contains all nodes in the same document as the context
5288 * node that are after the context node in document order, excluding any
5289 * descendants and excluding attribute nodes and namespace nodes; the nodes
5290 * are ordered in document order
5291 *
5292 * Returns the next element following that axis
5293 */
5294xmlNodePtr
5295xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5296 if (cur != NULL && cur->children != NULL)
5297 return cur->children ;
5298 if (cur == NULL) cur = ctxt->context->node;
5299 if (cur == NULL) return(NULL) ; /* ERROR */
5300 if (cur->next != NULL) return(cur->next) ;
5301 do {
5302 cur = cur->parent;
5303 if (cur == NULL) return(NULL);
5304 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5305 if (cur->next != NULL) return(cur->next);
5306 } while (cur != NULL);
5307 return(cur);
5308}
5309
5310/*
5311 * xmlXPathIsAncestor:
5312 * @ancestor: the ancestor node
5313 * @node: the current node
5314 *
5315 * Check that @ancestor is a @node's ancestor
5316 *
5317 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5318 */
5319static int
5320xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5321 if ((ancestor == NULL) || (node == NULL)) return(0);
5322 /* nodes need to be in the same document */
5323 if (ancestor->doc != node->doc) return(0);
5324 /* avoid searching if ancestor or node is the root node */
5325 if (ancestor == (xmlNodePtr) node->doc) return(1);
5326 if (node == (xmlNodePtr) ancestor->doc) return(0);
5327 while (node->parent != NULL) {
5328 if (node->parent == ancestor)
5329 return(1);
5330 node = node->parent;
5331 }
5332 return(0);
5333}
5334
5335/**
5336 * xmlXPathNextPreceding:
5337 * @ctxt: the XPath Parser context
5338 * @cur: the current node in the traversal
5339 *
5340 * Traversal function for the "preceding" direction
5341 * the preceding axis contains all nodes in the same document as the context
5342 * node that are before the context node in document order, excluding any
5343 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5344 * ordered in reverse document order
5345 *
5346 * Returns the next element following that axis
5347 */
5348xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005349xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5350{
Owen Taylor3473f882001-02-23 17:55:21 +00005351 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005352 cur = ctxt->context->node;
5353 if (cur == NULL)
5354 return (NULL);
5355 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5356 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005357 do {
5358 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005359 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5360 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005361 }
5362
5363 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005364 if (cur == NULL)
5365 return (NULL);
5366 if (cur == ctxt->context->doc->children)
5367 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005368 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005369 return (cur);
5370}
5371
5372/**
5373 * xmlXPathNextPrecedingInternal:
5374 * @ctxt: the XPath Parser context
5375 * @cur: the current node in the traversal
5376 *
5377 * Traversal function for the "preceding" direction
5378 * the preceding axis contains all nodes in the same document as the context
5379 * node that are before the context node in document order, excluding any
5380 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5381 * ordered in reverse document order
5382 * This is a faster implementation but internal only since it requires a
5383 * state kept in the parser context: ctxt->ancestor.
5384 *
5385 * Returns the next element following that axis
5386 */
5387static xmlNodePtr
5388xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5389 xmlNodePtr cur)
5390{
5391 if (cur == NULL) {
5392 cur = ctxt->context->node;
5393 if (cur == NULL)
5394 return (NULL);
5395 ctxt->ancestor = cur->parent;
5396 }
5397 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5398 cur = cur->prev;
5399 while (cur->prev == NULL) {
5400 cur = cur->parent;
5401 if (cur == NULL)
5402 return (NULL);
5403 if (cur == ctxt->context->doc->children)
5404 return (NULL);
5405 if (cur != ctxt->ancestor)
5406 return (cur);
5407 ctxt->ancestor = cur->parent;
5408 }
5409 cur = cur->prev;
5410 while (cur->last != NULL)
5411 cur = cur->last;
5412 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005413}
5414
5415/**
5416 * xmlXPathNextNamespace:
5417 * @ctxt: the XPath Parser context
5418 * @cur: the current attribute in the traversal
5419 *
5420 * Traversal function for the "namespace" direction
5421 * the namespace axis contains the namespace nodes of the context node;
5422 * the order of nodes on this axis is implementation-defined; the axis will
5423 * be empty unless the context node is an element
5424 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005425 * We keep the XML namespace node at the end of the list.
5426 *
Owen Taylor3473f882001-02-23 17:55:21 +00005427 * Returns the next element following that axis
5428 */
5429xmlNodePtr
5430xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005431 xmlNodePtr ret;
5432
Owen Taylor3473f882001-02-23 17:55:21 +00005433 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005434 if (cur == (xmlNodePtr) xmlXPathXMLNamespace)
5435 return(NULL);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005436 if ((cur == NULL) || (ctxt->context->tmpNsList == NULL)) {
5437 if (ctxt->context->tmpNsList != NULL)
5438 xmlFree(ctxt->context->tmpNsList);
5439 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005440 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005441 if (ctxt->context->tmpNsList == NULL) return(NULL);
5442 ctxt->context->tmpNsNr = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005443 }
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005444 ret = (xmlNodePtr)ctxt->context->tmpNsList[ctxt->context->tmpNsNr++];
5445 if (ret == NULL) {
5446 xmlFree(ctxt->context->tmpNsList);
5447 ctxt->context->tmpNsList = NULL;
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005448 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005449 }
5450 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005451}
5452
5453/**
5454 * xmlXPathNextAttribute:
5455 * @ctxt: the XPath Parser context
5456 * @cur: the current attribute in the traversal
5457 *
5458 * Traversal function for the "attribute" direction
5459 * TODO: support DTD inherited default attributes
5460 *
5461 * Returns the next element following that axis
5462 */
5463xmlNodePtr
5464xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005465 if (ctxt->context->node == NULL)
5466 return(NULL);
5467 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5468 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005469 if (cur == NULL) {
5470 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5471 return(NULL);
5472 return((xmlNodePtr)ctxt->context->node->properties);
5473 }
5474 return((xmlNodePtr)cur->next);
5475}
5476
5477/************************************************************************
5478 * *
5479 * NodeTest Functions *
5480 * *
5481 ************************************************************************/
5482
Owen Taylor3473f882001-02-23 17:55:21 +00005483#define IS_FUNCTION 200
5484
Owen Taylor3473f882001-02-23 17:55:21 +00005485
5486/************************************************************************
5487 * *
5488 * Implicit tree core function library *
5489 * *
5490 ************************************************************************/
5491
5492/**
5493 * xmlXPathRoot:
5494 * @ctxt: the XPath Parser context
5495 *
5496 * Initialize the context to the root of the document
5497 */
5498void
5499xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5500 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5501 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5502}
5503
5504/************************************************************************
5505 * *
5506 * The explicit core function library *
5507 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5508 * *
5509 ************************************************************************/
5510
5511
5512/**
5513 * xmlXPathLastFunction:
5514 * @ctxt: the XPath Parser context
5515 * @nargs: the number of arguments
5516 *
5517 * Implement the last() XPath function
5518 * number last()
5519 * The last function returns the number of nodes in the context node list.
5520 */
5521void
5522xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5523 CHECK_ARITY(0);
5524 if (ctxt->context->contextSize >= 0) {
5525 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5526#ifdef DEBUG_EXPR
5527 xmlGenericError(xmlGenericErrorContext,
5528 "last() : %d\n", ctxt->context->contextSize);
5529#endif
5530 } else {
5531 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5532 }
5533}
5534
5535/**
5536 * xmlXPathPositionFunction:
5537 * @ctxt: the XPath Parser context
5538 * @nargs: the number of arguments
5539 *
5540 * Implement the position() XPath function
5541 * number position()
5542 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005543 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00005544 * will be equal to last().
5545 */
5546void
5547xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5548 CHECK_ARITY(0);
5549 if (ctxt->context->proximityPosition >= 0) {
5550 valuePush(ctxt,
5551 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5552#ifdef DEBUG_EXPR
5553 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5554 ctxt->context->proximityPosition);
5555#endif
5556 } else {
5557 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5558 }
5559}
5560
5561/**
5562 * xmlXPathCountFunction:
5563 * @ctxt: the XPath Parser context
5564 * @nargs: the number of arguments
5565 *
5566 * Implement the count() XPath function
5567 * number count(node-set)
5568 */
5569void
5570xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5571 xmlXPathObjectPtr cur;
5572
5573 CHECK_ARITY(1);
5574 if ((ctxt->value == NULL) ||
5575 ((ctxt->value->type != XPATH_NODESET) &&
5576 (ctxt->value->type != XPATH_XSLT_TREE)))
5577 XP_ERROR(XPATH_INVALID_TYPE);
5578 cur = valuePop(ctxt);
5579
Daniel Veillard911f49a2001-04-07 15:39:35 +00005580 if ((cur == NULL) || (cur->nodesetval == NULL))
5581 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00005582 else if (cur->type == XPATH_NODESET) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00005583 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00005584 } else {
5585 if ((cur->nodesetval->nodeNr != 1) ||
5586 (cur->nodesetval->nodeTab == NULL)) {
5587 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5588 } else {
5589 xmlNodePtr tmp;
5590 int i = 0;
5591
5592 tmp = cur->nodesetval->nodeTab[0];
5593 if (tmp != NULL) {
5594 tmp = tmp->children;
5595 while (tmp != NULL) {
5596 tmp = tmp->next;
5597 i++;
5598 }
5599 }
5600 valuePush(ctxt, xmlXPathNewFloat((double) i));
5601 }
5602 }
Owen Taylor3473f882001-02-23 17:55:21 +00005603 xmlXPathFreeObject(cur);
5604}
5605
5606/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005607 * xmlXPathGetElementsByIds:
5608 * @doc: the document
5609 * @ids: a whitespace separated list of IDs
5610 *
5611 * Selects elements by their unique ID.
5612 *
5613 * Returns a node-set of selected elements.
5614 */
5615static xmlNodeSetPtr
5616xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5617 xmlNodeSetPtr ret;
5618 const xmlChar *cur = ids;
5619 xmlChar *ID;
5620 xmlAttrPtr attr;
5621 xmlNodePtr elem = NULL;
5622
5623 ret = xmlXPathNodeSetCreate(NULL);
5624
5625 while (IS_BLANK(*cur)) cur++;
5626 while (*cur != 0) {
5627 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
5628 (*cur == '.') || (*cur == '-') ||
5629 (*cur == '_') || (*cur == ':') ||
5630 (IS_COMBINING(*cur)) ||
5631 (IS_EXTENDER(*cur)))
5632 cur++;
5633
5634 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
5635
5636 ID = xmlStrndup(ids, cur - ids);
5637 attr = xmlGetID(doc, ID);
5638 if (attr != NULL) {
5639 elem = attr->parent;
5640 xmlXPathNodeSetAdd(ret, elem);
5641 }
5642 if (ID != NULL)
5643 xmlFree(ID);
5644
5645 while (IS_BLANK(*cur)) cur++;
5646 ids = cur;
5647 }
5648 return(ret);
5649}
5650
5651/**
Owen Taylor3473f882001-02-23 17:55:21 +00005652 * xmlXPathIdFunction:
5653 * @ctxt: the XPath Parser context
5654 * @nargs: the number of arguments
5655 *
5656 * Implement the id() XPath function
5657 * node-set id(object)
5658 * The id function selects elements by their unique ID
5659 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
5660 * then the result is the union of the result of applying id to the
5661 * string value of each of the nodes in the argument node-set. When the
5662 * argument to id is of any other type, the argument is converted to a
5663 * string as if by a call to the string function; the string is split
5664 * into a whitespace-separated list of tokens (whitespace is any sequence
5665 * of characters matching the production S); the result is a node-set
5666 * containing the elements in the same document as the context node that
5667 * have a unique ID equal to any of the tokens in the list.
5668 */
5669void
5670xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005671 xmlChar *tokens;
5672 xmlNodeSetPtr ret;
5673 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00005674
5675 CHECK_ARITY(1);
5676 obj = valuePop(ctxt);
5677 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
5678 if (obj->type == XPATH_NODESET) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005679 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00005680 int i;
5681
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005682 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005683
Daniel Veillard911f49a2001-04-07 15:39:35 +00005684 if (obj->nodesetval != NULL) {
5685 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005686 tokens =
5687 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
5688 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
5689 ret = xmlXPathNodeSetMerge(ret, ns);
5690 xmlXPathFreeNodeSet(ns);
5691 if (tokens != NULL)
5692 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00005693 }
Owen Taylor3473f882001-02-23 17:55:21 +00005694 }
5695
5696 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005697 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005698 return;
5699 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005700 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00005701
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005702 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
5703 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005704
Owen Taylor3473f882001-02-23 17:55:21 +00005705 xmlXPathFreeObject(obj);
5706 return;
5707}
5708
5709/**
5710 * xmlXPathLocalNameFunction:
5711 * @ctxt: the XPath Parser context
5712 * @nargs: the number of arguments
5713 *
5714 * Implement the local-name() XPath function
5715 * string local-name(node-set?)
5716 * The local-name function returns a string containing the local part
5717 * of the name of the node in the argument node-set that is first in
5718 * document order. If the node-set is empty or the first node has no
5719 * name, an empty string is returned. If the argument is omitted it
5720 * defaults to the context node.
5721 */
5722void
5723xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5724 xmlXPathObjectPtr cur;
5725
5726 if (nargs == 0) {
5727 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5728 nargs = 1;
5729 }
5730
5731 CHECK_ARITY(1);
5732 if ((ctxt->value == NULL) ||
5733 ((ctxt->value->type != XPATH_NODESET) &&
5734 (ctxt->value->type != XPATH_XSLT_TREE)))
5735 XP_ERROR(XPATH_INVALID_TYPE);
5736 cur = valuePop(ctxt);
5737
Daniel Veillard911f49a2001-04-07 15:39:35 +00005738 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005739 valuePush(ctxt, xmlXPathNewCString(""));
5740 } else {
5741 int i = 0; /* Should be first in document order !!!!! */
5742 switch (cur->nodesetval->nodeTab[i]->type) {
5743 case XML_ELEMENT_NODE:
5744 case XML_ATTRIBUTE_NODE:
5745 case XML_PI_NODE:
5746 valuePush(ctxt,
5747 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
5748 break;
5749 case XML_NAMESPACE_DECL:
5750 valuePush(ctxt, xmlXPathNewString(
5751 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
5752 break;
5753 default:
5754 valuePush(ctxt, xmlXPathNewCString(""));
5755 }
5756 }
5757 xmlXPathFreeObject(cur);
5758}
5759
5760/**
5761 * xmlXPathNamespaceURIFunction:
5762 * @ctxt: the XPath Parser context
5763 * @nargs: the number of arguments
5764 *
5765 * Implement the namespace-uri() XPath function
5766 * string namespace-uri(node-set?)
5767 * The namespace-uri function returns a string containing the
5768 * namespace URI of the expanded name of the node in the argument
5769 * node-set that is first in document order. If the node-set is empty,
5770 * the first node has no name, or the expanded name has no namespace
5771 * URI, an empty string is returned. If the argument is omitted it
5772 * defaults to the context node.
5773 */
5774void
5775xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5776 xmlXPathObjectPtr cur;
5777
5778 if (nargs == 0) {
5779 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5780 nargs = 1;
5781 }
5782 CHECK_ARITY(1);
5783 if ((ctxt->value == NULL) ||
5784 ((ctxt->value->type != XPATH_NODESET) &&
5785 (ctxt->value->type != XPATH_XSLT_TREE)))
5786 XP_ERROR(XPATH_INVALID_TYPE);
5787 cur = valuePop(ctxt);
5788
Daniel Veillard911f49a2001-04-07 15:39:35 +00005789 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005790 valuePush(ctxt, xmlXPathNewCString(""));
5791 } else {
5792 int i = 0; /* Should be first in document order !!!!! */
5793 switch (cur->nodesetval->nodeTab[i]->type) {
5794 case XML_ELEMENT_NODE:
5795 case XML_ATTRIBUTE_NODE:
5796 if (cur->nodesetval->nodeTab[i]->ns == NULL)
5797 valuePush(ctxt, xmlXPathNewCString(""));
5798 else
5799 valuePush(ctxt, xmlXPathNewString(
5800 cur->nodesetval->nodeTab[i]->ns->href));
5801 break;
5802 default:
5803 valuePush(ctxt, xmlXPathNewCString(""));
5804 }
5805 }
5806 xmlXPathFreeObject(cur);
5807}
5808
5809/**
5810 * xmlXPathNameFunction:
5811 * @ctxt: the XPath Parser context
5812 * @nargs: the number of arguments
5813 *
5814 * Implement the name() XPath function
5815 * string name(node-set?)
5816 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005817 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00005818 * order. The QName must represent the name with respect to the namespace
5819 * declarations in effect on the node whose name is being represented.
5820 * Typically, this will be the form in which the name occurred in the XML
5821 * source. This need not be the case if there are namespace declarations
5822 * in effect on the node that associate multiple prefixes with the same
5823 * namespace. However, an implementation may include information about
5824 * the original prefix in its representation of nodes; in this case, an
5825 * implementation can ensure that the returned string is always the same
5826 * as the QName used in the XML source. If the argument it omitted it
5827 * defaults to the context node.
5828 * Libxml keep the original prefix so the "real qualified name" used is
5829 * returned.
5830 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005831static void
Daniel Veillard04383752001-07-08 14:27:15 +00005832xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
5833{
Owen Taylor3473f882001-02-23 17:55:21 +00005834 xmlXPathObjectPtr cur;
5835
5836 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00005837 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5838 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00005839 }
5840
5841 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00005842 if ((ctxt->value == NULL) ||
5843 ((ctxt->value->type != XPATH_NODESET) &&
5844 (ctxt->value->type != XPATH_XSLT_TREE)))
5845 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00005846 cur = valuePop(ctxt);
5847
Daniel Veillard911f49a2001-04-07 15:39:35 +00005848 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00005849 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00005850 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00005851 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005852
Daniel Veillard04383752001-07-08 14:27:15 +00005853 switch (cur->nodesetval->nodeTab[i]->type) {
5854 case XML_ELEMENT_NODE:
5855 case XML_ATTRIBUTE_NODE:
5856 if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
5857 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL))
5858 valuePush(ctxt,
5859 xmlXPathNewString(cur->nodesetval->
5860 nodeTab[i]->name));
5861
5862 else {
5863 char name[2000];
5864
5865 snprintf(name, sizeof(name), "%s:%s",
5866 (char *) cur->nodesetval->nodeTab[i]->ns->
5867 prefix,
5868 (char *) cur->nodesetval->nodeTab[i]->name);
5869 name[sizeof(name) - 1] = 0;
5870 valuePush(ctxt, xmlXPathNewCString(name));
5871 }
5872 break;
5873 default:
5874 valuePush(ctxt,
5875 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
5876 xmlXPathLocalNameFunction(ctxt, 1);
5877 }
Owen Taylor3473f882001-02-23 17:55:21 +00005878 }
5879 xmlXPathFreeObject(cur);
5880}
5881
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005882
5883/**
Owen Taylor3473f882001-02-23 17:55:21 +00005884 * xmlXPathStringFunction:
5885 * @ctxt: the XPath Parser context
5886 * @nargs: the number of arguments
5887 *
5888 * Implement the string() XPath function
5889 * string string(object?)
5890 * he string function converts an object to a string as follows:
5891 * - A node-set is converted to a string by returning the value of
5892 * the node in the node-set that is first in document order.
5893 * If the node-set is empty, an empty string is returned.
5894 * - A number is converted to a string as follows
5895 * + NaN is converted to the string NaN
5896 * + positive zero is converted to the string 0
5897 * + negative zero is converted to the string 0
5898 * + positive infinity is converted to the string Infinity
5899 * + negative infinity is converted to the string -Infinity
5900 * + if the number is an integer, the number is represented in
5901 * decimal form as a Number with no decimal point and no leading
5902 * zeros, preceded by a minus sign (-) if the number is negative
5903 * + otherwise, the number is represented in decimal form as a
5904 * Number including a decimal point with at least one digit
5905 * before the decimal point and at least one digit after the
5906 * decimal point, preceded by a minus sign (-) if the number
5907 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005908 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00005909 * before the decimal point; beyond the one required digit
5910 * after the decimal point there must be as many, but only as
5911 * many, more digits as are needed to uniquely distinguish the
5912 * number from all other IEEE 754 numeric values.
5913 * - The boolean false value is converted to the string false.
5914 * The boolean true value is converted to the string true.
5915 *
5916 * If the argument is omitted, it defaults to a node-set with the
5917 * context node as its only member.
5918 */
5919void
5920xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5921 xmlXPathObjectPtr cur;
5922
5923 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005924 valuePush(ctxt,
5925 xmlXPathWrapString(
5926 xmlXPathCastNodeToString(ctxt->context->node)));
5927 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005928 }
5929
5930 CHECK_ARITY(1);
5931 cur = valuePop(ctxt);
5932 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005933 cur = xmlXPathConvertString(cur);
5934 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005935}
5936
5937/**
5938 * xmlXPathStringLengthFunction:
5939 * @ctxt: the XPath Parser context
5940 * @nargs: the number of arguments
5941 *
5942 * Implement the string-length() XPath function
5943 * number string-length(string?)
5944 * The string-length returns the number of characters in the string
5945 * (see [3.6 Strings]). If the argument is omitted, it defaults to
5946 * the context node converted to a string, in other words the value
5947 * of the context node.
5948 */
5949void
5950xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5951 xmlXPathObjectPtr cur;
5952
5953 if (nargs == 0) {
5954 if (ctxt->context->node == NULL) {
5955 valuePush(ctxt, xmlXPathNewFloat(0));
5956 } else {
5957 xmlChar *content;
5958
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005959 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00005960 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00005961 xmlFree(content);
5962 }
5963 return;
5964 }
5965 CHECK_ARITY(1);
5966 CAST_TO_STRING;
5967 CHECK_TYPE(XPATH_STRING);
5968 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00005969 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00005970 xmlXPathFreeObject(cur);
5971}
5972
5973/**
5974 * xmlXPathConcatFunction:
5975 * @ctxt: the XPath Parser context
5976 * @nargs: the number of arguments
5977 *
5978 * Implement the concat() XPath function
5979 * string concat(string, string, string*)
5980 * The concat function returns the concatenation of its arguments.
5981 */
5982void
5983xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5984 xmlXPathObjectPtr cur, newobj;
5985 xmlChar *tmp;
5986
5987 if (nargs < 2) {
5988 CHECK_ARITY(2);
5989 }
5990
5991 CAST_TO_STRING;
5992 cur = valuePop(ctxt);
5993 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
5994 xmlXPathFreeObject(cur);
5995 return;
5996 }
5997 nargs--;
5998
5999 while (nargs > 0) {
6000 CAST_TO_STRING;
6001 newobj = valuePop(ctxt);
6002 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6003 xmlXPathFreeObject(newobj);
6004 xmlXPathFreeObject(cur);
6005 XP_ERROR(XPATH_INVALID_TYPE);
6006 }
6007 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6008 newobj->stringval = cur->stringval;
6009 cur->stringval = tmp;
6010
6011 xmlXPathFreeObject(newobj);
6012 nargs--;
6013 }
6014 valuePush(ctxt, cur);
6015}
6016
6017/**
6018 * xmlXPathContainsFunction:
6019 * @ctxt: the XPath Parser context
6020 * @nargs: the number of arguments
6021 *
6022 * Implement the contains() XPath function
6023 * boolean contains(string, string)
6024 * The contains function returns true if the first argument string
6025 * contains the second argument string, and otherwise returns false.
6026 */
6027void
6028xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6029 xmlXPathObjectPtr hay, needle;
6030
6031 CHECK_ARITY(2);
6032 CAST_TO_STRING;
6033 CHECK_TYPE(XPATH_STRING);
6034 needle = valuePop(ctxt);
6035 CAST_TO_STRING;
6036 hay = valuePop(ctxt);
6037 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6038 xmlXPathFreeObject(hay);
6039 xmlXPathFreeObject(needle);
6040 XP_ERROR(XPATH_INVALID_TYPE);
6041 }
6042 if (xmlStrstr(hay->stringval, needle->stringval))
6043 valuePush(ctxt, xmlXPathNewBoolean(1));
6044 else
6045 valuePush(ctxt, xmlXPathNewBoolean(0));
6046 xmlXPathFreeObject(hay);
6047 xmlXPathFreeObject(needle);
6048}
6049
6050/**
6051 * xmlXPathStartsWithFunction:
6052 * @ctxt: the XPath Parser context
6053 * @nargs: the number of arguments
6054 *
6055 * Implement the starts-with() XPath function
6056 * boolean starts-with(string, string)
6057 * The starts-with function returns true if the first argument string
6058 * starts with the second argument string, and otherwise returns false.
6059 */
6060void
6061xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6062 xmlXPathObjectPtr hay, needle;
6063 int n;
6064
6065 CHECK_ARITY(2);
6066 CAST_TO_STRING;
6067 CHECK_TYPE(XPATH_STRING);
6068 needle = valuePop(ctxt);
6069 CAST_TO_STRING;
6070 hay = valuePop(ctxt);
6071 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6072 xmlXPathFreeObject(hay);
6073 xmlXPathFreeObject(needle);
6074 XP_ERROR(XPATH_INVALID_TYPE);
6075 }
6076 n = xmlStrlen(needle->stringval);
6077 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6078 valuePush(ctxt, xmlXPathNewBoolean(0));
6079 else
6080 valuePush(ctxt, xmlXPathNewBoolean(1));
6081 xmlXPathFreeObject(hay);
6082 xmlXPathFreeObject(needle);
6083}
6084
6085/**
6086 * xmlXPathSubstringFunction:
6087 * @ctxt: the XPath Parser context
6088 * @nargs: the number of arguments
6089 *
6090 * Implement the substring() XPath function
6091 * string substring(string, number, number?)
6092 * The substring function returns the substring of the first argument
6093 * starting at the position specified in the second argument with
6094 * length specified in the third argument. For example,
6095 * substring("12345",2,3) returns "234". If the third argument is not
6096 * specified, it returns the substring starting at the position specified
6097 * in the second argument and continuing to the end of the string. For
6098 * example, substring("12345",2) returns "2345". More precisely, each
6099 * character in the string (see [3.6 Strings]) is considered to have a
6100 * numeric position: the position of the first character is 1, the position
6101 * of the second character is 2 and so on. The returned substring contains
6102 * those characters for which the position of the character is greater than
6103 * or equal to the second argument and, if the third argument is specified,
6104 * less than the sum of the second and third arguments; the comparisons
6105 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6106 * - substring("12345", 1.5, 2.6) returns "234"
6107 * - substring("12345", 0, 3) returns "12"
6108 * - substring("12345", 0 div 0, 3) returns ""
6109 * - substring("12345", 1, 0 div 0) returns ""
6110 * - substring("12345", -42, 1 div 0) returns "12345"
6111 * - substring("12345", -1 div 0, 1 div 0) returns ""
6112 */
6113void
6114xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6115 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006116 double le=0, in;
6117 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006118 xmlChar *ret;
6119
Owen Taylor3473f882001-02-23 17:55:21 +00006120 if (nargs < 2) {
6121 CHECK_ARITY(2);
6122 }
6123 if (nargs > 3) {
6124 CHECK_ARITY(3);
6125 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006126 /*
6127 * take care of possible last (position) argument
6128 */
Owen Taylor3473f882001-02-23 17:55:21 +00006129 if (nargs == 3) {
6130 CAST_TO_NUMBER;
6131 CHECK_TYPE(XPATH_NUMBER);
6132 len = valuePop(ctxt);
6133 le = len->floatval;
6134 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006135 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006136
Owen Taylor3473f882001-02-23 17:55:21 +00006137 CAST_TO_NUMBER;
6138 CHECK_TYPE(XPATH_NUMBER);
6139 start = valuePop(ctxt);
6140 in = start->floatval;
6141 xmlXPathFreeObject(start);
6142 CAST_TO_STRING;
6143 CHECK_TYPE(XPATH_STRING);
6144 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006145 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006146
Daniel Veillard97ac1312001-05-30 19:14:17 +00006147 /*
6148 * If last pos not present, calculate last position
6149 */
6150 if (nargs != 3)
6151 le = m;
6152
6153 /*
6154 * To meet our requirements, initial index calculations
6155 * must be done before we convert to integer format
6156 *
6157 * First we normalize indices
6158 */
6159 in -= 1.0;
6160 le += in;
6161 if (in < 0.0)
6162 in = 0.0;
6163 if (le > (double)m)
6164 le = (double)m;
6165
6166 /*
6167 * Now we go to integer form, rounding up
6168 */
Owen Taylor3473f882001-02-23 17:55:21 +00006169 i = (int) in;
6170 if (((double)i) != in) i++;
6171
Owen Taylor3473f882001-02-23 17:55:21 +00006172 l = (int) le;
6173 if (((double)l) != le) l++;
6174
Daniel Veillard97ac1312001-05-30 19:14:17 +00006175 if (l > m) l=m;
Owen Taylor3473f882001-02-23 17:55:21 +00006176
6177 /* number of chars to copy */
6178 l -= i;
6179
Daniel Veillard97ac1312001-05-30 19:14:17 +00006180 ret = xmlUTF8Strsub(str->stringval, i, l);
Owen Taylor3473f882001-02-23 17:55:21 +00006181 if (ret == NULL)
6182 valuePush(ctxt, xmlXPathNewCString(""));
6183 else {
6184 valuePush(ctxt, xmlXPathNewString(ret));
6185 xmlFree(ret);
6186 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006187
Owen Taylor3473f882001-02-23 17:55:21 +00006188 xmlXPathFreeObject(str);
6189}
6190
6191/**
6192 * xmlXPathSubstringBeforeFunction:
6193 * @ctxt: the XPath Parser context
6194 * @nargs: the number of arguments
6195 *
6196 * Implement the substring-before() XPath function
6197 * string substring-before(string, string)
6198 * The substring-before function returns the substring of the first
6199 * argument string that precedes the first occurrence of the second
6200 * argument string in the first argument string, or the empty string
6201 * if the first argument string does not contain the second argument
6202 * string. For example, substring-before("1999/04/01","/") returns 1999.
6203 */
6204void
6205xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6206 xmlXPathObjectPtr str;
6207 xmlXPathObjectPtr find;
6208 xmlBufferPtr target;
6209 const xmlChar *point;
6210 int offset;
6211
6212 CHECK_ARITY(2);
6213 CAST_TO_STRING;
6214 find = valuePop(ctxt);
6215 CAST_TO_STRING;
6216 str = valuePop(ctxt);
6217
6218 target = xmlBufferCreate();
6219 if (target) {
6220 point = xmlStrstr(str->stringval, find->stringval);
6221 if (point) {
6222 offset = (int)(point - str->stringval);
6223 xmlBufferAdd(target, str->stringval, offset);
6224 }
6225 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6226 xmlBufferFree(target);
6227 }
6228
6229 xmlXPathFreeObject(str);
6230 xmlXPathFreeObject(find);
6231}
6232
6233/**
6234 * xmlXPathSubstringAfterFunction:
6235 * @ctxt: the XPath Parser context
6236 * @nargs: the number of arguments
6237 *
6238 * Implement the substring-after() XPath function
6239 * string substring-after(string, string)
6240 * The substring-after function returns the substring of the first
6241 * argument string that follows the first occurrence of the second
6242 * argument string in the first argument string, or the empty stringi
6243 * if the first argument string does not contain the second argument
6244 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6245 * and substring-after("1999/04/01","19") returns 99/04/01.
6246 */
6247void
6248xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6249 xmlXPathObjectPtr str;
6250 xmlXPathObjectPtr find;
6251 xmlBufferPtr target;
6252 const xmlChar *point;
6253 int offset;
6254
6255 CHECK_ARITY(2);
6256 CAST_TO_STRING;
6257 find = valuePop(ctxt);
6258 CAST_TO_STRING;
6259 str = valuePop(ctxt);
6260
6261 target = xmlBufferCreate();
6262 if (target) {
6263 point = xmlStrstr(str->stringval, find->stringval);
6264 if (point) {
6265 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6266 xmlBufferAdd(target, &str->stringval[offset],
6267 xmlStrlen(str->stringval) - offset);
6268 }
6269 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6270 xmlBufferFree(target);
6271 }
6272
6273 xmlXPathFreeObject(str);
6274 xmlXPathFreeObject(find);
6275}
6276
6277/**
6278 * xmlXPathNormalizeFunction:
6279 * @ctxt: the XPath Parser context
6280 * @nargs: the number of arguments
6281 *
6282 * Implement the normalize-space() XPath function
6283 * string normalize-space(string?)
6284 * The normalize-space function returns the argument string with white
6285 * space normalized by stripping leading and trailing whitespace
6286 * and replacing sequences of whitespace characters by a single
6287 * space. Whitespace characters are the same allowed by the S production
6288 * in XML. If the argument is omitted, it defaults to the context
6289 * node converted to a string, in other words the value of the context node.
6290 */
6291void
6292xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6293 xmlXPathObjectPtr obj = NULL;
6294 xmlChar *source = NULL;
6295 xmlBufferPtr target;
6296 xmlChar blank;
6297
6298 if (nargs == 0) {
6299 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006300 valuePush(ctxt,
6301 xmlXPathWrapString(
6302 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006303 nargs = 1;
6304 }
6305
6306 CHECK_ARITY(1);
6307 CAST_TO_STRING;
6308 CHECK_TYPE(XPATH_STRING);
6309 obj = valuePop(ctxt);
6310 source = obj->stringval;
6311
6312 target = xmlBufferCreate();
6313 if (target && source) {
6314
6315 /* Skip leading whitespaces */
6316 while (IS_BLANK(*source))
6317 source++;
6318
6319 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6320 blank = 0;
6321 while (*source) {
6322 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006323 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006324 } else {
6325 if (blank) {
6326 xmlBufferAdd(target, &blank, 1);
6327 blank = 0;
6328 }
6329 xmlBufferAdd(target, source, 1);
6330 }
6331 source++;
6332 }
6333
6334 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6335 xmlBufferFree(target);
6336 }
6337 xmlXPathFreeObject(obj);
6338}
6339
6340/**
6341 * xmlXPathTranslateFunction:
6342 * @ctxt: the XPath Parser context
6343 * @nargs: the number of arguments
6344 *
6345 * Implement the translate() XPath function
6346 * string translate(string, string, string)
6347 * The translate function returns the first argument string with
6348 * occurrences of characters in the second argument string replaced
6349 * by the character at the corresponding position in the third argument
6350 * string. For example, translate("bar","abc","ABC") returns the string
6351 * BAr. If there is a character in the second argument string with no
6352 * character at a corresponding position in the third argument string
6353 * (because the second argument string is longer than the third argument
6354 * string), then occurrences of that character in the first argument
6355 * string are removed. For example, translate("--aaa--","abc-","ABC")
6356 * returns "AAA". If a character occurs more than once in second
6357 * argument string, then the first occurrence determines the replacement
6358 * character. If the third argument string is longer than the second
6359 * argument string, then excess characters are ignored.
6360 */
6361void
6362xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006363 xmlXPathObjectPtr str;
6364 xmlXPathObjectPtr from;
6365 xmlXPathObjectPtr to;
6366 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006367 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006368 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006369 xmlChar *point;
6370 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006371
Daniel Veillarde043ee12001-04-16 14:08:07 +00006372 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006373
Daniel Veillarde043ee12001-04-16 14:08:07 +00006374 CAST_TO_STRING;
6375 to = valuePop(ctxt);
6376 CAST_TO_STRING;
6377 from = valuePop(ctxt);
6378 CAST_TO_STRING;
6379 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006380
Daniel Veillarde043ee12001-04-16 14:08:07 +00006381 target = xmlBufferCreate();
6382 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006383 max = xmlUTF8Strlen(to->stringval);
6384 for (cptr = str->stringval; (ch=*cptr); ) {
6385 offset = xmlUTF8Strloc(from->stringval, cptr);
6386 if (offset >= 0) {
6387 if (offset < max) {
6388 point = xmlUTF8Strpos(to->stringval, offset);
6389 if (point)
6390 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6391 }
6392 } else
6393 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6394
6395 /* Step to next character in input */
6396 cptr++;
6397 if ( ch & 0x80 ) {
6398 /* if not simple ascii, verify proper format */
6399 if ( (ch & 0xc0) != 0xc0 ) {
6400 xmlGenericError(xmlGenericErrorContext,
6401 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6402 break;
6403 }
6404 /* then skip over remaining bytes for this char */
6405 while ( (ch <<= 1) & 0x80 )
6406 if ( (*cptr++ & 0xc0) != 0x80 ) {
6407 xmlGenericError(xmlGenericErrorContext,
6408 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6409 break;
6410 }
6411 if (ch & 0x80) /* must have had error encountered */
6412 break;
6413 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006414 }
Owen Taylor3473f882001-02-23 17:55:21 +00006415 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006416 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6417 xmlBufferFree(target);
6418 xmlXPathFreeObject(str);
6419 xmlXPathFreeObject(from);
6420 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006421}
6422
6423/**
6424 * xmlXPathBooleanFunction:
6425 * @ctxt: the XPath Parser context
6426 * @nargs: the number of arguments
6427 *
6428 * Implement the boolean() XPath function
6429 * boolean boolean(object)
6430 * he boolean function converts its argument to a boolean as follows:
6431 * - a number is true if and only if it is neither positive or
6432 * negative zero nor NaN
6433 * - a node-set is true if and only if it is non-empty
6434 * - a string is true if and only if its length is non-zero
6435 */
6436void
6437xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6438 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006439
6440 CHECK_ARITY(1);
6441 cur = valuePop(ctxt);
6442 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006443 cur = xmlXPathConvertBoolean(cur);
6444 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006445}
6446
6447/**
6448 * xmlXPathNotFunction:
6449 * @ctxt: the XPath Parser context
6450 * @nargs: the number of arguments
6451 *
6452 * Implement the not() XPath function
6453 * boolean not(boolean)
6454 * The not function returns true if its argument is false,
6455 * and false otherwise.
6456 */
6457void
6458xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6459 CHECK_ARITY(1);
6460 CAST_TO_BOOLEAN;
6461 CHECK_TYPE(XPATH_BOOLEAN);
6462 ctxt->value->boolval = ! ctxt->value->boolval;
6463}
6464
6465/**
6466 * xmlXPathTrueFunction:
6467 * @ctxt: the XPath Parser context
6468 * @nargs: the number of arguments
6469 *
6470 * Implement the true() XPath function
6471 * boolean true()
6472 */
6473void
6474xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6475 CHECK_ARITY(0);
6476 valuePush(ctxt, xmlXPathNewBoolean(1));
6477}
6478
6479/**
6480 * xmlXPathFalseFunction:
6481 * @ctxt: the XPath Parser context
6482 * @nargs: the number of arguments
6483 *
6484 * Implement the false() XPath function
6485 * boolean false()
6486 */
6487void
6488xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6489 CHECK_ARITY(0);
6490 valuePush(ctxt, xmlXPathNewBoolean(0));
6491}
6492
6493/**
6494 * xmlXPathLangFunction:
6495 * @ctxt: the XPath Parser context
6496 * @nargs: the number of arguments
6497 *
6498 * Implement the lang() XPath function
6499 * boolean lang(string)
6500 * The lang function returns true or false depending on whether the
6501 * language of the context node as specified by xml:lang attributes
6502 * is the same as or is a sublanguage of the language specified by
6503 * the argument string. The language of the context node is determined
6504 * by the value of the xml:lang attribute on the context node, or, if
6505 * the context node has no xml:lang attribute, by the value of the
6506 * xml:lang attribute on the nearest ancestor of the context node that
6507 * has an xml:lang attribute. If there is no such attribute, then lang
6508 * returns false. If there is such an attribute, then lang returns
6509 * true if the attribute value is equal to the argument ignoring case,
6510 * or if there is some suffix starting with - such that the attribute
6511 * value is equal to the argument ignoring that suffix of the attribute
6512 * value and ignoring case.
6513 */
6514void
6515xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6516 xmlXPathObjectPtr val;
6517 const xmlChar *theLang;
6518 const xmlChar *lang;
6519 int ret = 0;
6520 int i;
6521
6522 CHECK_ARITY(1);
6523 CAST_TO_STRING;
6524 CHECK_TYPE(XPATH_STRING);
6525 val = valuePop(ctxt);
6526 lang = val->stringval;
6527 theLang = xmlNodeGetLang(ctxt->context->node);
6528 if ((theLang != NULL) && (lang != NULL)) {
6529 for (i = 0;lang[i] != 0;i++)
6530 if (toupper(lang[i]) != toupper(theLang[i]))
6531 goto not_equal;
6532 ret = 1;
6533 }
6534not_equal:
6535 xmlXPathFreeObject(val);
6536 valuePush(ctxt, xmlXPathNewBoolean(ret));
6537}
6538
6539/**
6540 * xmlXPathNumberFunction:
6541 * @ctxt: the XPath Parser context
6542 * @nargs: the number of arguments
6543 *
6544 * Implement the number() XPath function
6545 * number number(object?)
6546 */
6547void
6548xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6549 xmlXPathObjectPtr cur;
6550 double res;
6551
6552 if (nargs == 0) {
6553 if (ctxt->context->node == NULL) {
6554 valuePush(ctxt, xmlXPathNewFloat(0.0));
6555 } else {
6556 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6557
6558 res = xmlXPathStringEvalNumber(content);
6559 valuePush(ctxt, xmlXPathNewFloat(res));
6560 xmlFree(content);
6561 }
6562 return;
6563 }
6564
6565 CHECK_ARITY(1);
6566 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006567 cur = xmlXPathConvertNumber(cur);
6568 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006569}
6570
6571/**
6572 * xmlXPathSumFunction:
6573 * @ctxt: the XPath Parser context
6574 * @nargs: the number of arguments
6575 *
6576 * Implement the sum() XPath function
6577 * number sum(node-set)
6578 * The sum function returns the sum of the values of the nodes in
6579 * the argument node-set.
6580 */
6581void
6582xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6583 xmlXPathObjectPtr cur;
6584 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006585 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00006586
6587 CHECK_ARITY(1);
6588 if ((ctxt->value == NULL) ||
6589 ((ctxt->value->type != XPATH_NODESET) &&
6590 (ctxt->value->type != XPATH_XSLT_TREE)))
6591 XP_ERROR(XPATH_INVALID_TYPE);
6592 cur = valuePop(ctxt);
6593
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006594 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006595 valuePush(ctxt, xmlXPathNewFloat(0.0));
6596 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006597 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
6598 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006599 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006600 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00006601 }
6602 xmlXPathFreeObject(cur);
6603}
6604
6605/**
6606 * xmlXPathFloorFunction:
6607 * @ctxt: the XPath Parser context
6608 * @nargs: the number of arguments
6609 *
6610 * Implement the floor() XPath function
6611 * number floor(number)
6612 * The floor function returns the largest (closest to positive infinity)
6613 * number that is not greater than the argument and that is an integer.
6614 */
6615void
6616xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006617 double f;
6618
Owen Taylor3473f882001-02-23 17:55:21 +00006619 CHECK_ARITY(1);
6620 CAST_TO_NUMBER;
6621 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006622
6623 f = (double)((int) ctxt->value->floatval);
6624 if (f != ctxt->value->floatval) {
6625 if (ctxt->value->floatval > 0)
6626 ctxt->value->floatval = f;
6627 else
6628 ctxt->value->floatval = f - 1;
6629 }
Owen Taylor3473f882001-02-23 17:55:21 +00006630}
6631
6632/**
6633 * xmlXPathCeilingFunction:
6634 * @ctxt: the XPath Parser context
6635 * @nargs: the number of arguments
6636 *
6637 * Implement the ceiling() XPath function
6638 * number ceiling(number)
6639 * The ceiling function returns the smallest (closest to negative infinity)
6640 * number that is not less than the argument and that is an integer.
6641 */
6642void
6643xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6644 double f;
6645
6646 CHECK_ARITY(1);
6647 CAST_TO_NUMBER;
6648 CHECK_TYPE(XPATH_NUMBER);
6649
6650#if 0
6651 ctxt->value->floatval = ceil(ctxt->value->floatval);
6652#else
6653 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006654 if (f != ctxt->value->floatval) {
6655 if (ctxt->value->floatval > 0)
6656 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00006657 else {
6658 if (ctxt->value->floatval < 0 && f == 0)
6659 ctxt->value->floatval = xmlXPathNZERO;
6660 else
6661 ctxt->value->floatval = f;
6662 }
6663
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006664 }
Owen Taylor3473f882001-02-23 17:55:21 +00006665#endif
6666}
6667
6668/**
6669 * xmlXPathRoundFunction:
6670 * @ctxt: the XPath Parser context
6671 * @nargs: the number of arguments
6672 *
6673 * Implement the round() XPath function
6674 * number round(number)
6675 * The round function returns the number that is closest to the
6676 * argument and that is an integer. If there are two such numbers,
6677 * then the one that is even is returned.
6678 */
6679void
6680xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6681 double f;
6682
6683 CHECK_ARITY(1);
6684 CAST_TO_NUMBER;
6685 CHECK_TYPE(XPATH_NUMBER);
6686
Daniel Veillardcda96922001-08-21 10:56:31 +00006687 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
6688 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
6689 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00006690 (ctxt->value->floatval == 0.0))
6691 return;
6692
Owen Taylor3473f882001-02-23 17:55:21 +00006693 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006694 if (ctxt->value->floatval < 0) {
6695 if (ctxt->value->floatval < f - 0.5)
6696 ctxt->value->floatval = f - 1;
6697 else
6698 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00006699 if (ctxt->value->floatval == 0)
6700 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006701 } else {
6702 if (ctxt->value->floatval < f + 0.5)
6703 ctxt->value->floatval = f;
6704 else
6705 ctxt->value->floatval = f + 1;
6706 }
Owen Taylor3473f882001-02-23 17:55:21 +00006707}
6708
6709/************************************************************************
6710 * *
6711 * The Parser *
6712 * *
6713 ************************************************************************/
6714
6715/*
6716 * a couple of forward declarations since we use a recursive call based
6717 * implementation.
6718 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006719static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006720static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006721static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006722#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006723static void xmlXPathCompRelLocationPath(xmlXPathParserContextPtr ctxt);
6724#define xmlXPathCompRelativeLocationPath xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00006725#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006726static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006727#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00006728static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
6729 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00006730
6731/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00006732 * xmlXPathCurrentChar:
6733 * @ctxt: the XPath parser context
6734 * @cur: pointer to the beginning of the char
6735 * @len: pointer to the length of the char read
6736 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006737 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00006738 * bytes in the input buffer.
6739 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006740 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00006741 */
6742
6743static int
6744xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
6745 unsigned char c;
6746 unsigned int val;
6747 const xmlChar *cur;
6748
6749 if (ctxt == NULL)
6750 return(0);
6751 cur = ctxt->cur;
6752
6753 /*
6754 * We are supposed to handle UTF8, check it's valid
6755 * From rfc2044: encoding of the Unicode values on UTF-8:
6756 *
6757 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
6758 * 0000 0000-0000 007F 0xxxxxxx
6759 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
6760 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
6761 *
6762 * Check for the 0x110000 limit too
6763 */
6764 c = *cur;
6765 if (c & 0x80) {
6766 if ((cur[1] & 0xc0) != 0x80)
6767 goto encoding_error;
6768 if ((c & 0xe0) == 0xe0) {
6769
6770 if ((cur[2] & 0xc0) != 0x80)
6771 goto encoding_error;
6772 if ((c & 0xf0) == 0xf0) {
6773 if (((c & 0xf8) != 0xf0) ||
6774 ((cur[3] & 0xc0) != 0x80))
6775 goto encoding_error;
6776 /* 4-byte code */
6777 *len = 4;
6778 val = (cur[0] & 0x7) << 18;
6779 val |= (cur[1] & 0x3f) << 12;
6780 val |= (cur[2] & 0x3f) << 6;
6781 val |= cur[3] & 0x3f;
6782 } else {
6783 /* 3-byte code */
6784 *len = 3;
6785 val = (cur[0] & 0xf) << 12;
6786 val |= (cur[1] & 0x3f) << 6;
6787 val |= cur[2] & 0x3f;
6788 }
6789 } else {
6790 /* 2-byte code */
6791 *len = 2;
6792 val = (cur[0] & 0x1f) << 6;
6793 val |= cur[1] & 0x3f;
6794 }
6795 if (!IS_CHAR(val)) {
6796 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
6797 }
6798 return(val);
6799 } else {
6800 /* 1-byte code */
6801 *len = 1;
6802 return((int) *cur);
6803 }
6804encoding_error:
6805 /*
6806 * If we detect an UTF8 error that probably mean that the
6807 * input encoding didn't get properly advertized in the
6808 * declaration header. Report the error and switch the encoding
6809 * to ISO-Latin-1 (if you don't like this policy, just declare the
6810 * encoding !)
6811 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00006812 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00006813 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00006814}
6815
6816/**
Owen Taylor3473f882001-02-23 17:55:21 +00006817 * xmlXPathParseNCName:
6818 * @ctxt: the XPath Parser context
6819 *
6820 * parse an XML namespace non qualified name.
6821 *
6822 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
6823 *
6824 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
6825 * CombiningChar | Extender
6826 *
6827 * Returns the namespace name or NULL
6828 */
6829
6830xmlChar *
6831xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00006832 const xmlChar *in;
6833 xmlChar *ret;
6834 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006835
Daniel Veillard2156a562001-04-28 12:24:34 +00006836 /*
6837 * Accelerator for simple ASCII names
6838 */
6839 in = ctxt->cur;
6840 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6841 ((*in >= 0x41) && (*in <= 0x5A)) ||
6842 (*in == '_')) {
6843 in++;
6844 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6845 ((*in >= 0x41) && (*in <= 0x5A)) ||
6846 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00006847 (*in == '_') || (*in == '.') ||
6848 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00006849 in++;
6850 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
6851 (*in == '[') || (*in == ']') || (*in == ':') ||
6852 (*in == '@') || (*in == '*')) {
6853 count = in - ctxt->cur;
6854 if (count == 0)
6855 return(NULL);
6856 ret = xmlStrndup(ctxt->cur, count);
6857 ctxt->cur = in;
6858 return(ret);
6859 }
6860 }
6861 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00006862}
6863
Daniel Veillard2156a562001-04-28 12:24:34 +00006864
Owen Taylor3473f882001-02-23 17:55:21 +00006865/**
6866 * xmlXPathParseQName:
6867 * @ctxt: the XPath Parser context
6868 * @prefix: a xmlChar **
6869 *
6870 * parse an XML qualified name
6871 *
6872 * [NS 5] QName ::= (Prefix ':')? LocalPart
6873 *
6874 * [NS 6] Prefix ::= NCName
6875 *
6876 * [NS 7] LocalPart ::= NCName
6877 *
6878 * Returns the function returns the local part, and prefix is updated
6879 * to get the Prefix if any.
6880 */
6881
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006882static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006883xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
6884 xmlChar *ret = NULL;
6885
6886 *prefix = NULL;
6887 ret = xmlXPathParseNCName(ctxt);
6888 if (CUR == ':') {
6889 *prefix = ret;
6890 NEXT;
6891 ret = xmlXPathParseNCName(ctxt);
6892 }
6893 return(ret);
6894}
6895
6896/**
6897 * xmlXPathParseName:
6898 * @ctxt: the XPath Parser context
6899 *
6900 * parse an XML name
6901 *
6902 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
6903 * CombiningChar | Extender
6904 *
6905 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
6906 *
6907 * Returns the namespace name or NULL
6908 */
6909
6910xmlChar *
6911xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006912 const xmlChar *in;
6913 xmlChar *ret;
6914 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006915
Daniel Veillard61d80a22001-04-27 17:13:01 +00006916 /*
6917 * Accelerator for simple ASCII names
6918 */
6919 in = ctxt->cur;
6920 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6921 ((*in >= 0x41) && (*in <= 0x5A)) ||
6922 (*in == '_') || (*in == ':')) {
6923 in++;
6924 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6925 ((*in >= 0x41) && (*in <= 0x5A)) ||
6926 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00006927 (*in == '_') || (*in == '-') ||
6928 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00006929 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00006930 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006931 count = in - ctxt->cur;
6932 ret = xmlStrndup(ctxt->cur, count);
6933 ctxt->cur = in;
6934 return(ret);
6935 }
6936 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006937 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00006938}
6939
Daniel Veillard61d80a22001-04-27 17:13:01 +00006940static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00006941xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006942 xmlChar buf[XML_MAX_NAMELEN + 5];
6943 int len = 0, l;
6944 int c;
6945
6946 /*
6947 * Handler for more complex cases
6948 */
6949 c = CUR_CHAR(l);
6950 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00006951 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
6952 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00006953 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00006954 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006955 return(NULL);
6956 }
6957
6958 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
6959 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
6960 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00006961 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00006962 (IS_COMBINING(c)) ||
6963 (IS_EXTENDER(c)))) {
6964 COPY_BUF(l,buf,len,c);
6965 NEXTL(l);
6966 c = CUR_CHAR(l);
6967 if (len >= XML_MAX_NAMELEN) {
6968 /*
6969 * Okay someone managed to make a huge name, so he's ready to pay
6970 * for the processing speed.
6971 */
6972 xmlChar *buffer;
6973 int max = len * 2;
6974
6975 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
6976 if (buffer == NULL) {
6977 XP_ERROR0(XPATH_MEMORY_ERROR);
6978 }
6979 memcpy(buffer, buf, len);
6980 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
6981 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00006982 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00006983 (IS_COMBINING(c)) ||
6984 (IS_EXTENDER(c))) {
6985 if (len + 10 > max) {
6986 max *= 2;
6987 buffer = (xmlChar *) xmlRealloc(buffer,
6988 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00006989 if (buffer == NULL) {
6990 XP_ERROR0(XPATH_MEMORY_ERROR);
6991 }
6992 }
6993 COPY_BUF(l,buffer,len,c);
6994 NEXTL(l);
6995 c = CUR_CHAR(l);
6996 }
6997 buffer[len] = 0;
6998 return(buffer);
6999 }
7000 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007001 if (len == 0)
7002 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007003 return(xmlStrndup(buf, len));
7004}
Owen Taylor3473f882001-02-23 17:55:21 +00007005/**
7006 * xmlXPathStringEvalNumber:
7007 * @str: A string to scan
7008 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00007009 * [30a] Float ::= Number ('e' Digits?)?
7010 *
Owen Taylor3473f882001-02-23 17:55:21 +00007011 * [30] Number ::= Digits ('.' Digits?)?
7012 * | '.' Digits
7013 * [31] Digits ::= [0-9]+
7014 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007015 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00007016 * In complement of the Number expression, this function also handles
7017 * negative values : '-' Number.
7018 *
7019 * Returns the double value.
7020 */
7021double
7022xmlXPathStringEvalNumber(const xmlChar *str) {
7023 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00007024 double ret;
Owen Taylor3473f882001-02-23 17:55:21 +00007025 double mult = 1;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007026 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007027 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007028 int exponent = 0;
7029 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007030#ifdef __GNUC__
7031 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007032 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007033#endif
Bjorn Reese70a9da52001-04-21 16:57:29 +00007034
Owen Taylor3473f882001-02-23 17:55:21 +00007035 while (IS_BLANK(*cur)) cur++;
7036 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7037 return(xmlXPathNAN);
7038 }
7039 if (*cur == '-') {
7040 isneg = 1;
7041 cur++;
7042 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007043
7044#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007045 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007046 * tmp/temp is a workaround against a gcc compiler bug
7047 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007048 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007049 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007050 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007051 ret = ret * 10;
7052 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00007053 ok = 1;
7054 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00007055 temp = (double) tmp;
7056 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007057 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007058#else
Daniel Veillard7b416132002-03-07 08:36:03 +00007059 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007060 while ((*cur >= '0') && (*cur <= '9')) {
7061 ret = ret * 10 + (*cur - '0');
7062 ok = 1;
7063 cur++;
7064 }
7065#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007066
Owen Taylor3473f882001-02-23 17:55:21 +00007067 if (*cur == '.') {
7068 cur++;
7069 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7070 return(xmlXPathNAN);
7071 }
7072 while ((*cur >= '0') && (*cur <= '9')) {
7073 mult /= 10;
7074 ret = ret + (*cur - '0') * mult;
7075 cur++;
7076 }
7077 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007078 if ((*cur == 'e') || (*cur == 'E')) {
7079 cur++;
7080 if (*cur == '-') {
7081 is_exponent_negative = 1;
7082 cur++;
7083 }
7084 while ((*cur >= '0') && (*cur <= '9')) {
7085 exponent = exponent * 10 + (*cur - '0');
7086 cur++;
7087 }
7088 }
Owen Taylor3473f882001-02-23 17:55:21 +00007089 while (IS_BLANK(*cur)) cur++;
7090 if (*cur != 0) return(xmlXPathNAN);
7091 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007092 if (is_exponent_negative) exponent = -exponent;
7093 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007094 return(ret);
7095}
7096
7097/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007098 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007099 * @ctxt: the XPath Parser context
7100 *
7101 * [30] Number ::= Digits ('.' Digits?)?
7102 * | '.' Digits
7103 * [31] Digits ::= [0-9]+
7104 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007105 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007106 *
7107 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007108static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007109xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7110{
Owen Taylor3473f882001-02-23 17:55:21 +00007111 double ret = 0.0;
7112 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007113 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007114 int exponent = 0;
7115 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007116#ifdef __GNUC__
7117 unsigned long tmp = 0;
7118 double temp;
7119#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007120
7121 CHECK_ERROR;
7122 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7123 XP_ERROR(XPATH_NUMBER_ERROR);
7124 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007125#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007126 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007127 * tmp/temp is a workaround against a gcc compiler bug
7128 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007129 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007130 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007131 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007132 ret = ret * 10;
7133 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007134 ok = 1;
7135 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007136 temp = (double) tmp;
7137 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007138 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007139#else
7140 ret = 0;
7141 while ((CUR >= '0') && (CUR <= '9')) {
7142 ret = ret * 10 + (CUR - '0');
7143 ok = 1;
7144 NEXT;
7145 }
7146#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007147 if (CUR == '.') {
7148 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007149 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7150 XP_ERROR(XPATH_NUMBER_ERROR);
7151 }
7152 while ((CUR >= '0') && (CUR <= '9')) {
7153 mult /= 10;
7154 ret = ret + (CUR - '0') * mult;
7155 NEXT;
7156 }
Owen Taylor3473f882001-02-23 17:55:21 +00007157 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007158 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007159 NEXT;
7160 if (CUR == '-') {
7161 is_exponent_negative = 1;
7162 NEXT;
7163 }
7164 while ((CUR >= '0') && (CUR <= '9')) {
7165 exponent = exponent * 10 + (CUR - '0');
7166 NEXT;
7167 }
7168 if (is_exponent_negative)
7169 exponent = -exponent;
7170 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007171 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007172 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007173 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007174}
7175
7176/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007177 * xmlXPathParseLiteral:
7178 * @ctxt: the XPath Parser context
7179 *
7180 * Parse a Literal
7181 *
7182 * [29] Literal ::= '"' [^"]* '"'
7183 * | "'" [^']* "'"
7184 *
7185 * Returns the value found or NULL in case of error
7186 */
7187static xmlChar *
7188xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7189 const xmlChar *q;
7190 xmlChar *ret = NULL;
7191
7192 if (CUR == '"') {
7193 NEXT;
7194 q = CUR_PTR;
7195 while ((IS_CHAR(CUR)) && (CUR != '"'))
7196 NEXT;
7197 if (!IS_CHAR(CUR)) {
7198 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7199 } else {
7200 ret = xmlStrndup(q, CUR_PTR - q);
7201 NEXT;
7202 }
7203 } else if (CUR == '\'') {
7204 NEXT;
7205 q = CUR_PTR;
7206 while ((IS_CHAR(CUR)) && (CUR != '\''))
7207 NEXT;
7208 if (!IS_CHAR(CUR)) {
7209 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7210 } else {
7211 ret = xmlStrndup(q, CUR_PTR - q);
7212 NEXT;
7213 }
7214 } else {
7215 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7216 }
7217 return(ret);
7218}
7219
7220/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007221 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007222 * @ctxt: the XPath Parser context
7223 *
7224 * Parse a Literal and push it on the stack.
7225 *
7226 * [29] Literal ::= '"' [^"]* '"'
7227 * | "'" [^']* "'"
7228 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007229 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007230 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007231static void
7232xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007233 const xmlChar *q;
7234 xmlChar *ret = NULL;
7235
7236 if (CUR == '"') {
7237 NEXT;
7238 q = CUR_PTR;
7239 while ((IS_CHAR(CUR)) && (CUR != '"'))
7240 NEXT;
7241 if (!IS_CHAR(CUR)) {
7242 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7243 } else {
7244 ret = xmlStrndup(q, CUR_PTR - q);
7245 NEXT;
7246 }
7247 } else if (CUR == '\'') {
7248 NEXT;
7249 q = CUR_PTR;
7250 while ((IS_CHAR(CUR)) && (CUR != '\''))
7251 NEXT;
7252 if (!IS_CHAR(CUR)) {
7253 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7254 } else {
7255 ret = xmlStrndup(q, CUR_PTR - q);
7256 NEXT;
7257 }
7258 } else {
7259 XP_ERROR(XPATH_START_LITERAL_ERROR);
7260 }
7261 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007262 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7263 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007264 xmlFree(ret);
7265}
7266
7267/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007268 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007269 * @ctxt: the XPath Parser context
7270 *
7271 * Parse a VariableReference, evaluate it and push it on the stack.
7272 *
7273 * The variable bindings consist of a mapping from variable names
7274 * to variable values. The value of a variable is an object, which
7275 * of any of the types that are possible for the value of an expression,
7276 * and may also be of additional types not specified here.
7277 *
7278 * Early evaluation is possible since:
7279 * The variable bindings [...] used to evaluate a subexpression are
7280 * always the same as those used to evaluate the containing expression.
7281 *
7282 * [36] VariableReference ::= '$' QName
7283 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007284static void
7285xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007286 xmlChar *name;
7287 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007288
7289 SKIP_BLANKS;
7290 if (CUR != '$') {
7291 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7292 }
7293 NEXT;
7294 name = xmlXPathParseQName(ctxt, &prefix);
7295 if (name == NULL) {
7296 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7297 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007298 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007299 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7300 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007301 SKIP_BLANKS;
7302}
7303
7304/**
7305 * xmlXPathIsNodeType:
7306 * @ctxt: the XPath Parser context
7307 * @name: a name string
7308 *
7309 * Is the name given a NodeType one.
7310 *
7311 * [38] NodeType ::= 'comment'
7312 * | 'text'
7313 * | 'processing-instruction'
7314 * | 'node'
7315 *
7316 * Returns 1 if true 0 otherwise
7317 */
7318int
7319xmlXPathIsNodeType(const xmlChar *name) {
7320 if (name == NULL)
7321 return(0);
7322
Daniel Veillard1971ee22002-01-31 20:29:19 +00007323 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007324 return(1);
7325 if (xmlStrEqual(name, BAD_CAST "text"))
7326 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007327 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007328 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007329 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007330 return(1);
7331 return(0);
7332}
7333
7334/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007335 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007336 * @ctxt: the XPath Parser context
7337 *
7338 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7339 * [17] Argument ::= Expr
7340 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007341 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007342 * pushed on the stack
7343 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007344static void
7345xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007346 xmlChar *name;
7347 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007348 int nbargs = 0;
7349
7350 name = xmlXPathParseQName(ctxt, &prefix);
7351 if (name == NULL) {
7352 XP_ERROR(XPATH_EXPR_ERROR);
7353 }
7354 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007355#ifdef DEBUG_EXPR
7356 if (prefix == NULL)
7357 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7358 name);
7359 else
7360 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7361 prefix, name);
7362#endif
7363
Owen Taylor3473f882001-02-23 17:55:21 +00007364 if (CUR != '(') {
7365 XP_ERROR(XPATH_EXPR_ERROR);
7366 }
7367 NEXT;
7368 SKIP_BLANKS;
7369
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007370 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007371 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007372 int op1 = ctxt->comp->last;
7373 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007374 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007375 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007376 nbargs++;
7377 if (CUR == ')') break;
7378 if (CUR != ',') {
7379 XP_ERROR(XPATH_EXPR_ERROR);
7380 }
7381 NEXT;
7382 SKIP_BLANKS;
7383 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007384 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7385 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007386 NEXT;
7387 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007388}
7389
7390/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007391 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007392 * @ctxt: the XPath Parser context
7393 *
7394 * [15] PrimaryExpr ::= VariableReference
7395 * | '(' Expr ')'
7396 * | Literal
7397 * | Number
7398 * | FunctionCall
7399 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007400 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007401 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007402static void
7403xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007404 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007405 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007406 else if (CUR == '(') {
7407 NEXT;
7408 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007409 xmlXPathCompileExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007410 if (CUR != ')') {
7411 XP_ERROR(XPATH_EXPR_ERROR);
7412 }
7413 NEXT;
7414 SKIP_BLANKS;
7415 } else if (IS_DIGIT(CUR)) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007416 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007417 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007418 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007419 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007420 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007421 }
7422 SKIP_BLANKS;
7423}
7424
7425/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007426 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007427 * @ctxt: the XPath Parser context
7428 *
7429 * [20] FilterExpr ::= PrimaryExpr
7430 * | FilterExpr Predicate
7431 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007432 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007433 * Square brackets are used to filter expressions in the same way that
7434 * they are used in location paths. It is an error if the expression to
7435 * be filtered does not evaluate to a node-set. The context node list
7436 * used for evaluating the expression in square brackets is the node-set
7437 * to be filtered listed in document order.
7438 */
7439
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007440static void
7441xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
7442 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007443 CHECK_ERROR;
7444 SKIP_BLANKS;
7445
7446 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007447 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00007448 SKIP_BLANKS;
7449 }
7450
7451
7452}
7453
7454/**
7455 * xmlXPathScanName:
7456 * @ctxt: the XPath Parser context
7457 *
7458 * Trickery: parse an XML name but without consuming the input flow
7459 * Needed to avoid insanity in the parser state.
7460 *
7461 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7462 * CombiningChar | Extender
7463 *
7464 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7465 *
7466 * [6] Names ::= Name (S Name)*
7467 *
7468 * Returns the Name parsed or NULL
7469 */
7470
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007471static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007472xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7473 xmlChar buf[XML_MAX_NAMELEN];
7474 int len = 0;
7475
7476 SKIP_BLANKS;
7477 if (!IS_LETTER(CUR) && (CUR != '_') &&
7478 (CUR != ':')) {
7479 return(NULL);
7480 }
7481
7482 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7483 (NXT(len) == '.') || (NXT(len) == '-') ||
7484 (NXT(len) == '_') || (NXT(len) == ':') ||
7485 (IS_COMBINING(NXT(len))) ||
7486 (IS_EXTENDER(NXT(len)))) {
7487 buf[len] = NXT(len);
7488 len++;
7489 if (len >= XML_MAX_NAMELEN) {
7490 xmlGenericError(xmlGenericErrorContext,
7491 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
7492 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7493 (NXT(len) == '.') || (NXT(len) == '-') ||
7494 (NXT(len) == '_') || (NXT(len) == ':') ||
7495 (IS_COMBINING(NXT(len))) ||
7496 (IS_EXTENDER(NXT(len))))
7497 len++;
7498 break;
7499 }
7500 }
7501 return(xmlStrndup(buf, len));
7502}
7503
7504/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007505 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007506 * @ctxt: the XPath Parser context
7507 *
7508 * [19] PathExpr ::= LocationPath
7509 * | FilterExpr
7510 * | FilterExpr '/' RelativeLocationPath
7511 * | FilterExpr '//' RelativeLocationPath
7512 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007513 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007514 * The / operator and // operators combine an arbitrary expression
7515 * and a relative location path. It is an error if the expression
7516 * does not evaluate to a node-set.
7517 * The / operator does composition in the same way as when / is
7518 * used in a location path. As in location paths, // is short for
7519 * /descendant-or-self::node()/.
7520 */
7521
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007522static void
7523xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007524 int lc = 1; /* Should we branch to LocationPath ? */
7525 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7526
7527 SKIP_BLANKS;
7528 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
7529 (CUR == '\'') || (CUR == '"')) {
7530 lc = 0;
7531 } else if (CUR == '*') {
7532 /* relative or absolute location path */
7533 lc = 1;
7534 } else if (CUR == '/') {
7535 /* relative or absolute location path */
7536 lc = 1;
7537 } else if (CUR == '@') {
7538 /* relative abbreviated attribute location path */
7539 lc = 1;
7540 } else if (CUR == '.') {
7541 /* relative abbreviated attribute location path */
7542 lc = 1;
7543 } else {
7544 /*
7545 * Problem is finding if we have a name here whether it's:
7546 * - a nodetype
7547 * - a function call in which case it's followed by '('
7548 * - an axis in which case it's followed by ':'
7549 * - a element name
7550 * We do an a priori analysis here rather than having to
7551 * maintain parsed token content through the recursive function
7552 * calls. This looks uglier but makes the code quite easier to
7553 * read/write/debug.
7554 */
7555 SKIP_BLANKS;
7556 name = xmlXPathScanName(ctxt);
7557 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7558#ifdef DEBUG_STEP
7559 xmlGenericError(xmlGenericErrorContext,
7560 "PathExpr: Axis\n");
7561#endif
7562 lc = 1;
7563 xmlFree(name);
7564 } else if (name != NULL) {
7565 int len =xmlStrlen(name);
7566 int blank = 0;
7567
7568
7569 while (NXT(len) != 0) {
7570 if (NXT(len) == '/') {
7571 /* element name */
7572#ifdef DEBUG_STEP
7573 xmlGenericError(xmlGenericErrorContext,
7574 "PathExpr: AbbrRelLocation\n");
7575#endif
7576 lc = 1;
7577 break;
7578 } else if (IS_BLANK(NXT(len))) {
7579 /* skip to next */
7580 blank = 1;
7581 } else if (NXT(len) == ':') {
7582#ifdef DEBUG_STEP
7583 xmlGenericError(xmlGenericErrorContext,
7584 "PathExpr: AbbrRelLocation\n");
7585#endif
7586 lc = 1;
7587 break;
7588 } else if ((NXT(len) == '(')) {
7589 /* Note Type or Function */
7590 if (xmlXPathIsNodeType(name)) {
7591#ifdef DEBUG_STEP
7592 xmlGenericError(xmlGenericErrorContext,
7593 "PathExpr: Type search\n");
7594#endif
7595 lc = 1;
7596 } else {
7597#ifdef DEBUG_STEP
7598 xmlGenericError(xmlGenericErrorContext,
7599 "PathExpr: function call\n");
7600#endif
7601 lc = 0;
7602 }
7603 break;
7604 } else if ((NXT(len) == '[')) {
7605 /* element name */
7606#ifdef DEBUG_STEP
7607 xmlGenericError(xmlGenericErrorContext,
7608 "PathExpr: AbbrRelLocation\n");
7609#endif
7610 lc = 1;
7611 break;
7612 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
7613 (NXT(len) == '=')) {
7614 lc = 1;
7615 break;
7616 } else {
7617 lc = 1;
7618 break;
7619 }
7620 len++;
7621 }
7622 if (NXT(len) == 0) {
7623#ifdef DEBUG_STEP
7624 xmlGenericError(xmlGenericErrorContext,
7625 "PathExpr: AbbrRelLocation\n");
7626#endif
7627 /* element name */
7628 lc = 1;
7629 }
7630 xmlFree(name);
7631 } else {
7632 /* make sure all cases are covered explicitely */
7633 XP_ERROR(XPATH_EXPR_ERROR);
7634 }
7635 }
7636
7637 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007638 if (CUR == '/') {
7639 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
7640 } else {
7641 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007642 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007643 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007644 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007645 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007646 CHECK_ERROR;
7647 if ((CUR == '/') && (NXT(1) == '/')) {
7648 SKIP(2);
7649 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007650
7651 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7652 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
7653 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
7654
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007655 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007656 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007657 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007658 }
7659 }
7660 SKIP_BLANKS;
7661}
7662
7663/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007664 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007665 * @ctxt: the XPath Parser context
7666 *
7667 * [18] UnionExpr ::= PathExpr
7668 * | UnionExpr '|' PathExpr
7669 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007670 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007671 */
7672
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007673static void
7674xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
7675 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007676 CHECK_ERROR;
7677 SKIP_BLANKS;
7678 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007679 int op1 = ctxt->comp->last;
7680 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007681
7682 NEXT;
7683 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007684 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007685
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007686 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
7687
Owen Taylor3473f882001-02-23 17:55:21 +00007688 SKIP_BLANKS;
7689 }
Owen Taylor3473f882001-02-23 17:55:21 +00007690}
7691
7692/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007693 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007694 * @ctxt: the XPath Parser context
7695 *
7696 * [27] UnaryExpr ::= UnionExpr
7697 * | '-' UnaryExpr
7698 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007699 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007700 */
7701
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007702static void
7703xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007704 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007705 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007706
7707 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00007708 while (CUR == '-') {
7709 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007710 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007711 NEXT;
7712 SKIP_BLANKS;
7713 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007714
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007715 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007716 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007717 if (found) {
7718 if (minus)
7719 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
7720 else
7721 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007722 }
7723}
7724
7725/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007726 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007727 * @ctxt: the XPath Parser context
7728 *
7729 * [26] MultiplicativeExpr ::= UnaryExpr
7730 * | MultiplicativeExpr MultiplyOperator UnaryExpr
7731 * | MultiplicativeExpr 'div' UnaryExpr
7732 * | MultiplicativeExpr 'mod' UnaryExpr
7733 * [34] MultiplyOperator ::= '*'
7734 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007735 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007736 */
7737
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007738static void
7739xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
7740 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007741 CHECK_ERROR;
7742 SKIP_BLANKS;
7743 while ((CUR == '*') ||
7744 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
7745 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
7746 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007747 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007748
7749 if (CUR == '*') {
7750 op = 0;
7751 NEXT;
7752 } else if (CUR == 'd') {
7753 op = 1;
7754 SKIP(3);
7755 } else if (CUR == 'm') {
7756 op = 2;
7757 SKIP(3);
7758 }
7759 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007760 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007761 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007762 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007763 SKIP_BLANKS;
7764 }
7765}
7766
7767/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007768 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007769 * @ctxt: the XPath Parser context
7770 *
7771 * [25] AdditiveExpr ::= MultiplicativeExpr
7772 * | AdditiveExpr '+' MultiplicativeExpr
7773 * | AdditiveExpr '-' MultiplicativeExpr
7774 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007775 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007776 */
7777
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007778static void
7779xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007780
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007781 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007782 CHECK_ERROR;
7783 SKIP_BLANKS;
7784 while ((CUR == '+') || (CUR == '-')) {
7785 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007786 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007787
7788 if (CUR == '+') plus = 1;
7789 else plus = 0;
7790 NEXT;
7791 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007792 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007793 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007794 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007795 SKIP_BLANKS;
7796 }
7797}
7798
7799/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007800 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007801 * @ctxt: the XPath Parser context
7802 *
7803 * [24] RelationalExpr ::= AdditiveExpr
7804 * | RelationalExpr '<' AdditiveExpr
7805 * | RelationalExpr '>' AdditiveExpr
7806 * | RelationalExpr '<=' AdditiveExpr
7807 * | RelationalExpr '>=' AdditiveExpr
7808 *
7809 * A <= B > C is allowed ? Answer from James, yes with
7810 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
7811 * which is basically what got implemented.
7812 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007813 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00007814 * on the stack
7815 */
7816
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007817static void
7818xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
7819 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007820 CHECK_ERROR;
7821 SKIP_BLANKS;
7822 while ((CUR == '<') ||
7823 (CUR == '>') ||
7824 ((CUR == '<') && (NXT(1) == '=')) ||
7825 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007826 int inf, strict;
7827 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007828
7829 if (CUR == '<') inf = 1;
7830 else inf = 0;
7831 if (NXT(1) == '=') strict = 0;
7832 else strict = 1;
7833 NEXT;
7834 if (!strict) NEXT;
7835 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007836 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007837 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007838 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00007839 SKIP_BLANKS;
7840 }
7841}
7842
7843/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007844 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007845 * @ctxt: the XPath Parser context
7846 *
7847 * [23] EqualityExpr ::= RelationalExpr
7848 * | EqualityExpr '=' RelationalExpr
7849 * | EqualityExpr '!=' RelationalExpr
7850 *
7851 * A != B != C is allowed ? Answer from James, yes with
7852 * (RelationalExpr = RelationalExpr) = RelationalExpr
7853 * (RelationalExpr != RelationalExpr) != RelationalExpr
7854 * which is basically what got implemented.
7855 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007856 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007857 *
7858 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007859static void
7860xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
7861 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007862 CHECK_ERROR;
7863 SKIP_BLANKS;
7864 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007865 int eq;
7866 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007867
7868 if (CUR == '=') eq = 1;
7869 else eq = 0;
7870 NEXT;
7871 if (!eq) NEXT;
7872 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007873 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007874 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007875 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007876 SKIP_BLANKS;
7877 }
7878}
7879
7880/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007881 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007882 * @ctxt: the XPath Parser context
7883 *
7884 * [22] AndExpr ::= EqualityExpr
7885 * | AndExpr 'and' EqualityExpr
7886 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007887 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007888 *
7889 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007890static void
7891xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
7892 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007893 CHECK_ERROR;
7894 SKIP_BLANKS;
7895 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007896 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007897 SKIP(3);
7898 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007899 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007900 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007901 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007902 SKIP_BLANKS;
7903 }
7904}
7905
7906/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007907 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007908 * @ctxt: the XPath Parser context
7909 *
7910 * [14] Expr ::= OrExpr
7911 * [21] OrExpr ::= AndExpr
7912 * | OrExpr 'or' AndExpr
7913 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007914 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00007915 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007916static void
7917xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
7918 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007919 CHECK_ERROR;
7920 SKIP_BLANKS;
7921 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007922 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007923 SKIP(2);
7924 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007925 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007926 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007927 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
7928 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00007929 SKIP_BLANKS;
7930 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007931 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
7932 /* more ops could be optimized too */
7933 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
7934 }
Owen Taylor3473f882001-02-23 17:55:21 +00007935}
7936
7937/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007938 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00007939 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007940 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00007941 *
7942 * [8] Predicate ::= '[' PredicateExpr ']'
7943 * [9] PredicateExpr ::= Expr
7944 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007945 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00007946 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007947static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007948xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007949 int op1 = ctxt->comp->last;
7950
7951 SKIP_BLANKS;
7952 if (CUR != '[') {
7953 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7954 }
7955 NEXT;
7956 SKIP_BLANKS;
7957
7958 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007959 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007960 CHECK_ERROR;
7961
7962 if (CUR != ']') {
7963 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7964 }
7965
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007966 if (filter)
7967 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
7968 else
7969 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007970
7971 NEXT;
7972 SKIP_BLANKS;
7973}
7974
7975/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007976 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00007977 * @ctxt: the XPath Parser context
7978 * @test: pointer to a xmlXPathTestVal
7979 * @type: pointer to a xmlXPathTypeVal
7980 * @prefix: placeholder for a possible name prefix
7981 *
7982 * [7] NodeTest ::= NameTest
7983 * | NodeType '(' ')'
7984 * | 'processing-instruction' '(' Literal ')'
7985 *
7986 * [37] NameTest ::= '*'
7987 * | NCName ':' '*'
7988 * | QName
7989 * [38] NodeType ::= 'comment'
7990 * | 'text'
7991 * | 'processing-instruction'
7992 * | 'node'
7993 *
7994 * Returns the name found and update @test, @type and @prefix appropriately
7995 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007996static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007997xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
7998 xmlXPathTypeVal *type, const xmlChar **prefix,
7999 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008000 int blanks;
8001
8002 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8003 STRANGE;
8004 return(NULL);
8005 }
8006 *type = 0;
8007 *test = 0;
8008 *prefix = NULL;
8009 SKIP_BLANKS;
8010
8011 if ((name == NULL) && (CUR == '*')) {
8012 /*
8013 * All elements
8014 */
8015 NEXT;
8016 *test = NODE_TEST_ALL;
8017 return(NULL);
8018 }
8019
8020 if (name == NULL)
8021 name = xmlXPathParseNCName(ctxt);
8022 if (name == NULL) {
8023 XP_ERROR0(XPATH_EXPR_ERROR);
8024 }
8025
8026 blanks = IS_BLANK(CUR);
8027 SKIP_BLANKS;
8028 if (CUR == '(') {
8029 NEXT;
8030 /*
8031 * NodeType or PI search
8032 */
8033 if (xmlStrEqual(name, BAD_CAST "comment"))
8034 *type = NODE_TYPE_COMMENT;
8035 else if (xmlStrEqual(name, BAD_CAST "node"))
8036 *type = NODE_TYPE_NODE;
8037 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8038 *type = NODE_TYPE_PI;
8039 else if (xmlStrEqual(name, BAD_CAST "text"))
8040 *type = NODE_TYPE_TEXT;
8041 else {
8042 if (name != NULL)
8043 xmlFree(name);
8044 XP_ERROR0(XPATH_EXPR_ERROR);
8045 }
8046
8047 *test = NODE_TEST_TYPE;
8048
8049 SKIP_BLANKS;
8050 if (*type == NODE_TYPE_PI) {
8051 /*
8052 * Specific case: search a PI by name.
8053 */
Owen Taylor3473f882001-02-23 17:55:21 +00008054 if (name != NULL)
8055 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008056 name = NULL;
8057 if (CUR != ')') {
8058 name = xmlXPathParseLiteral(ctxt);
8059 CHECK_ERROR 0;
8060 SKIP_BLANKS;
8061 }
Owen Taylor3473f882001-02-23 17:55:21 +00008062 }
8063 if (CUR != ')') {
8064 if (name != NULL)
8065 xmlFree(name);
8066 XP_ERROR0(XPATH_UNCLOSED_ERROR);
8067 }
8068 NEXT;
8069 return(name);
8070 }
8071 *test = NODE_TEST_NAME;
8072 if ((!blanks) && (CUR == ':')) {
8073 NEXT;
8074
8075 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008076 * Since currently the parser context don't have a
8077 * namespace list associated:
8078 * The namespace name for this prefix can be computed
8079 * only at evaluation time. The compilation is done
8080 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008081 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008082#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008083 *prefix = xmlXPathNsLookup(ctxt->context, name);
8084 if (name != NULL)
8085 xmlFree(name);
8086 if (*prefix == NULL) {
8087 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8088 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008089#else
8090 *prefix = name;
8091#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008092
8093 if (CUR == '*') {
8094 /*
8095 * All elements
8096 */
8097 NEXT;
8098 *test = NODE_TEST_ALL;
8099 return(NULL);
8100 }
8101
8102 name = xmlXPathParseNCName(ctxt);
8103 if (name == NULL) {
8104 XP_ERROR0(XPATH_EXPR_ERROR);
8105 }
8106 }
8107 return(name);
8108}
8109
8110/**
8111 * xmlXPathIsAxisName:
8112 * @name: a preparsed name token
8113 *
8114 * [6] AxisName ::= 'ancestor'
8115 * | 'ancestor-or-self'
8116 * | 'attribute'
8117 * | 'child'
8118 * | 'descendant'
8119 * | 'descendant-or-self'
8120 * | 'following'
8121 * | 'following-sibling'
8122 * | 'namespace'
8123 * | 'parent'
8124 * | 'preceding'
8125 * | 'preceding-sibling'
8126 * | 'self'
8127 *
8128 * Returns the axis or 0
8129 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008130static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008131xmlXPathIsAxisName(const xmlChar *name) {
8132 xmlXPathAxisVal ret = 0;
8133 switch (name[0]) {
8134 case 'a':
8135 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8136 ret = AXIS_ANCESTOR;
8137 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8138 ret = AXIS_ANCESTOR_OR_SELF;
8139 if (xmlStrEqual(name, BAD_CAST "attribute"))
8140 ret = AXIS_ATTRIBUTE;
8141 break;
8142 case 'c':
8143 if (xmlStrEqual(name, BAD_CAST "child"))
8144 ret = AXIS_CHILD;
8145 break;
8146 case 'd':
8147 if (xmlStrEqual(name, BAD_CAST "descendant"))
8148 ret = AXIS_DESCENDANT;
8149 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8150 ret = AXIS_DESCENDANT_OR_SELF;
8151 break;
8152 case 'f':
8153 if (xmlStrEqual(name, BAD_CAST "following"))
8154 ret = AXIS_FOLLOWING;
8155 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8156 ret = AXIS_FOLLOWING_SIBLING;
8157 break;
8158 case 'n':
8159 if (xmlStrEqual(name, BAD_CAST "namespace"))
8160 ret = AXIS_NAMESPACE;
8161 break;
8162 case 'p':
8163 if (xmlStrEqual(name, BAD_CAST "parent"))
8164 ret = AXIS_PARENT;
8165 if (xmlStrEqual(name, BAD_CAST "preceding"))
8166 ret = AXIS_PRECEDING;
8167 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8168 ret = AXIS_PRECEDING_SIBLING;
8169 break;
8170 case 's':
8171 if (xmlStrEqual(name, BAD_CAST "self"))
8172 ret = AXIS_SELF;
8173 break;
8174 }
8175 return(ret);
8176}
8177
8178/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008179 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008180 * @ctxt: the XPath Parser context
8181 *
8182 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8183 * | AbbreviatedStep
8184 *
8185 * [12] AbbreviatedStep ::= '.' | '..'
8186 *
8187 * [5] AxisSpecifier ::= AxisName '::'
8188 * | AbbreviatedAxisSpecifier
8189 *
8190 * [13] AbbreviatedAxisSpecifier ::= '@'?
8191 *
8192 * Modified for XPtr range support as:
8193 *
8194 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8195 * | AbbreviatedStep
8196 * | 'range-to' '(' Expr ')' Predicate*
8197 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008198 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008199 * A location step of . is short for self::node(). This is
8200 * particularly useful in conjunction with //. For example, the
8201 * location path .//para is short for
8202 * self::node()/descendant-or-self::node()/child::para
8203 * and so will select all para descendant elements of the context
8204 * node.
8205 * Similarly, a location step of .. is short for parent::node().
8206 * For example, ../title is short for parent::node()/child::title
8207 * and so will select the title children of the parent of the context
8208 * node.
8209 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008210static void
8211xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008212#ifdef LIBXML_XPTR_ENABLED
8213 int rangeto = 0;
8214 int op2 = -1;
8215#endif
8216
Owen Taylor3473f882001-02-23 17:55:21 +00008217 SKIP_BLANKS;
8218 if ((CUR == '.') && (NXT(1) == '.')) {
8219 SKIP(2);
8220 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008221 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8222 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008223 } else if (CUR == '.') {
8224 NEXT;
8225 SKIP_BLANKS;
8226 } else {
8227 xmlChar *name = NULL;
8228 const xmlChar *prefix = NULL;
8229 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008230 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008231 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008232 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008233
8234 /*
8235 * The modification needed for XPointer change to the production
8236 */
8237#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008238 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008239 name = xmlXPathParseNCName(ctxt);
8240 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008241 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008242 xmlFree(name);
8243 SKIP_BLANKS;
8244 if (CUR != '(') {
8245 XP_ERROR(XPATH_EXPR_ERROR);
8246 }
8247 NEXT;
8248 SKIP_BLANKS;
8249
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008250 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008251 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008252 CHECK_ERROR;
8253
8254 SKIP_BLANKS;
8255 if (CUR != ')') {
8256 XP_ERROR(XPATH_EXPR_ERROR);
8257 }
8258 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008259 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008260 goto eval_predicates;
8261 }
8262 }
8263#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008264 if (CUR == '*') {
8265 axis = AXIS_CHILD;
8266 } else {
8267 if (name == NULL)
8268 name = xmlXPathParseNCName(ctxt);
8269 if (name != NULL) {
8270 axis = xmlXPathIsAxisName(name);
8271 if (axis != 0) {
8272 SKIP_BLANKS;
8273 if ((CUR == ':') && (NXT(1) == ':')) {
8274 SKIP(2);
8275 xmlFree(name);
8276 name = NULL;
8277 } else {
8278 /* an element name can conflict with an axis one :-\ */
8279 axis = AXIS_CHILD;
8280 }
Owen Taylor3473f882001-02-23 17:55:21 +00008281 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008282 axis = AXIS_CHILD;
8283 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008284 } else if (CUR == '@') {
8285 NEXT;
8286 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008287 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008288 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008289 }
Owen Taylor3473f882001-02-23 17:55:21 +00008290 }
8291
8292 CHECK_ERROR;
8293
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008294 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008295 if (test == 0)
8296 return;
8297
8298#ifdef DEBUG_STEP
8299 xmlGenericError(xmlGenericErrorContext,
8300 "Basis : computing new set\n");
8301#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008302
Owen Taylor3473f882001-02-23 17:55:21 +00008303#ifdef DEBUG_STEP
8304 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008305 if (ctxt->value == NULL)
8306 xmlGenericError(xmlGenericErrorContext, "no value\n");
8307 else if (ctxt->value->nodesetval == NULL)
8308 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8309 else
8310 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008311#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008312
8313eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008314 op1 = ctxt->comp->last;
8315 ctxt->comp->last = -1;
8316
Owen Taylor3473f882001-02-23 17:55:21 +00008317 SKIP_BLANKS;
8318 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008319 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008320 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008321
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008322#ifdef LIBXML_XPTR_ENABLED
8323 if (rangeto) {
8324 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8325 } else
8326#endif
8327 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8328 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008329
Owen Taylor3473f882001-02-23 17:55:21 +00008330 }
8331#ifdef DEBUG_STEP
8332 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008333 if (ctxt->value == NULL)
8334 xmlGenericError(xmlGenericErrorContext, "no value\n");
8335 else if (ctxt->value->nodesetval == NULL)
8336 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8337 else
8338 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8339 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008340#endif
8341}
8342
8343/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008344 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008345 * @ctxt: the XPath Parser context
8346 *
8347 * [3] RelativeLocationPath ::= Step
8348 * | RelativeLocationPath '/' Step
8349 * | AbbreviatedRelativeLocationPath
8350 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8351 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008352 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008353 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008354static void
Owen Taylor3473f882001-02-23 17:55:21 +00008355#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008356xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008357#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008358xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008359#endif
8360(xmlXPathParserContextPtr ctxt) {
8361 SKIP_BLANKS;
8362 if ((CUR == '/') && (NXT(1) == '/')) {
8363 SKIP(2);
8364 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008365 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8366 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008367 } else if (CUR == '/') {
8368 NEXT;
8369 SKIP_BLANKS;
8370 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008371 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008372 SKIP_BLANKS;
8373 while (CUR == '/') {
8374 if ((CUR == '/') && (NXT(1) == '/')) {
8375 SKIP(2);
8376 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008377 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008378 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008379 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008380 } else if (CUR == '/') {
8381 NEXT;
8382 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008383 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008384 }
8385 SKIP_BLANKS;
8386 }
8387}
8388
8389/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008390 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008391 * @ctxt: the XPath Parser context
8392 *
8393 * [1] LocationPath ::= RelativeLocationPath
8394 * | AbsoluteLocationPath
8395 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8396 * | AbbreviatedAbsoluteLocationPath
8397 * [10] AbbreviatedAbsoluteLocationPath ::=
8398 * '//' RelativeLocationPath
8399 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008400 * Compile a location path
8401 *
Owen Taylor3473f882001-02-23 17:55:21 +00008402 * // is short for /descendant-or-self::node()/. For example,
8403 * //para is short for /descendant-or-self::node()/child::para and
8404 * so will select any para element in the document (even a para element
8405 * that is a document element will be selected by //para since the
8406 * document element node is a child of the root node); div//para is
8407 * short for div/descendant-or-self::node()/child::para and so will
8408 * select all para descendants of div children.
8409 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008410static void
8411xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008412 SKIP_BLANKS;
8413 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008414 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008415 } else {
8416 while (CUR == '/') {
8417 if ((CUR == '/') && (NXT(1) == '/')) {
8418 SKIP(2);
8419 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008420 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8421 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008422 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008423 } else if (CUR == '/') {
8424 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008425 SKIP_BLANKS;
8426 if ((CUR != 0 ) &&
8427 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
8428 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008429 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008430 }
8431 }
8432 }
8433}
8434
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008435/************************************************************************
8436 * *
8437 * XPath precompiled expression evaluation *
8438 * *
8439 ************************************************************************/
8440
Daniel Veillardf06307e2001-07-03 10:35:50 +00008441static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008442xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8443
8444/**
8445 * xmlXPathNodeCollectAndTest:
8446 * @ctxt: the XPath Parser context
8447 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008448 * @first: pointer to the first element in document order
8449 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008450 *
8451 * This is the function implementing a step: based on the current list
8452 * of nodes, it builds up a new list, looking at all nodes under that
8453 * axis and selecting them it also do the predicate filtering
8454 *
8455 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00008456 *
8457 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008458 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008459static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008460xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008461 xmlXPathStepOpPtr op,
8462 xmlNodePtr * first, xmlNodePtr * last)
8463{
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008464 xmlXPathAxisVal axis = op->value;
8465 xmlXPathTestVal test = op->value2;
8466 xmlXPathTypeVal type = op->value3;
8467 const xmlChar *prefix = op->value4;
8468 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008469 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008470
8471#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008472 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008473#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008474 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008475 xmlNodeSetPtr ret, list;
8476 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008477 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00008478 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008479 xmlNodePtr cur = NULL;
8480 xmlXPathObjectPtr obj;
8481 xmlNodeSetPtr nodelist;
8482 xmlNodePtr tmp;
8483
Daniel Veillardf06307e2001-07-03 10:35:50 +00008484 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008485 obj = valuePop(ctxt);
8486 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00008487 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008488 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008489 URI = xmlXPathNsLookup(ctxt->context, prefix);
8490 if (URI == NULL)
8491 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008492 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008493#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008494 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008495#endif
8496 switch (axis) {
8497 case AXIS_ANCESTOR:
8498#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008499 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008500#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008501 first = NULL;
8502 next = xmlXPathNextAncestor;
8503 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008504 case AXIS_ANCESTOR_OR_SELF:
8505#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008506 xmlGenericError(xmlGenericErrorContext,
8507 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008508#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008509 first = NULL;
8510 next = xmlXPathNextAncestorOrSelf;
8511 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008512 case AXIS_ATTRIBUTE:
8513#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008514 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008515#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008516 first = NULL;
8517 last = NULL;
8518 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00008519 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008520 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008521 case AXIS_CHILD:
8522#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008523 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008524#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008525 last = NULL;
8526 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00008527 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008528 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008529 case AXIS_DESCENDANT:
8530#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008531 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008532#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008533 last = NULL;
8534 next = xmlXPathNextDescendant;
8535 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008536 case AXIS_DESCENDANT_OR_SELF:
8537#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008538 xmlGenericError(xmlGenericErrorContext,
8539 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008540#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008541 last = NULL;
8542 next = xmlXPathNextDescendantOrSelf;
8543 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008544 case AXIS_FOLLOWING:
8545#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008546 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008547#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008548 last = NULL;
8549 next = xmlXPathNextFollowing;
8550 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008551 case AXIS_FOLLOWING_SIBLING:
8552#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008553 xmlGenericError(xmlGenericErrorContext,
8554 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008555#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008556 last = NULL;
8557 next = xmlXPathNextFollowingSibling;
8558 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008559 case AXIS_NAMESPACE:
8560#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008561 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008562#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008563 first = NULL;
8564 last = NULL;
8565 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00008566 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008567 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008568 case AXIS_PARENT:
8569#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008570 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008571#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008572 first = NULL;
8573 next = xmlXPathNextParent;
8574 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008575 case AXIS_PRECEDING:
8576#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008577 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008578#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008579 first = NULL;
8580 next = xmlXPathNextPrecedingInternal;
8581 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008582 case AXIS_PRECEDING_SIBLING:
8583#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008584 xmlGenericError(xmlGenericErrorContext,
8585 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008586#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008587 first = NULL;
8588 next = xmlXPathNextPrecedingSibling;
8589 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008590 case AXIS_SELF:
8591#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008592 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008593#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008594 first = NULL;
8595 last = NULL;
8596 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00008597 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008598 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008599 }
8600 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008601 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008602
8603 nodelist = obj->nodesetval;
8604 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008605 xmlXPathFreeObject(obj);
8606 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8607 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008608 }
8609 addNode = xmlXPathNodeSetAddUnique;
8610 ret = NULL;
8611#ifdef DEBUG_STEP
8612 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008613 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008614 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008615 case NODE_TEST_NONE:
8616 xmlGenericError(xmlGenericErrorContext,
8617 " searching for none !!!\n");
8618 break;
8619 case NODE_TEST_TYPE:
8620 xmlGenericError(xmlGenericErrorContext,
8621 " searching for type %d\n", type);
8622 break;
8623 case NODE_TEST_PI:
8624 xmlGenericError(xmlGenericErrorContext,
8625 " searching for PI !!!\n");
8626 break;
8627 case NODE_TEST_ALL:
8628 xmlGenericError(xmlGenericErrorContext,
8629 " searching for *\n");
8630 break;
8631 case NODE_TEST_NS:
8632 xmlGenericError(xmlGenericErrorContext,
8633 " searching for namespace %s\n",
8634 prefix);
8635 break;
8636 case NODE_TEST_NAME:
8637 xmlGenericError(xmlGenericErrorContext,
8638 " searching for name %s\n", name);
8639 if (prefix != NULL)
8640 xmlGenericError(xmlGenericErrorContext,
8641 " with namespace %s\n", prefix);
8642 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008643 }
8644 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8645#endif
8646 /*
8647 * 2.3 Node Tests
8648 * - For the attribute axis, the principal node type is attribute.
8649 * - For the namespace axis, the principal node type is namespace.
8650 * - For other axes, the principal node type is element.
8651 *
8652 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008653 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008654 * select all element children of the context node
8655 */
8656 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008657 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008658 ctxt->context->node = nodelist->nodeTab[i];
8659
Daniel Veillardf06307e2001-07-03 10:35:50 +00008660 cur = NULL;
8661 list = xmlXPathNodeSetCreate(NULL);
8662 do {
8663 cur = next(ctxt, cur);
8664 if (cur == NULL)
8665 break;
8666 if ((first != NULL) && (*first == cur))
8667 break;
8668 if (((t % 256) == 0) &&
8669 (first != NULL) && (*first != NULL) &&
8670 (xmlXPathCmpNodes(*first, cur) >= 0))
8671 break;
8672 if ((last != NULL) && (*last == cur))
8673 break;
8674 if (((t % 256) == 0) &&
8675 (last != NULL) && (*last != NULL) &&
8676 (xmlXPathCmpNodes(cur, *last) >= 0))
8677 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008678 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008679#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008680 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
8681#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008682 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008683 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008684 ctxt->context->node = tmp;
8685 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008686 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008687 if ((cur->type == type) ||
8688 ((type == NODE_TYPE_NODE) &&
8689 ((cur->type == XML_DOCUMENT_NODE) ||
8690 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8691 (cur->type == XML_ELEMENT_NODE) ||
8692 (cur->type == XML_PI_NODE) ||
8693 (cur->type == XML_COMMENT_NODE) ||
8694 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00008695 (cur->type == XML_TEXT_NODE))) ||
8696 ((type == NODE_TYPE_TEXT) &&
8697 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008698#ifdef DEBUG_STEP
8699 n++;
8700#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008701 addNode(list, cur);
8702 }
8703 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008704 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008705 if (cur->type == XML_PI_NODE) {
8706 if ((name != NULL) &&
8707 (!xmlStrEqual(name, cur->name)))
8708 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008709#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008710 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008711#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008712 addNode(list, cur);
8713 }
8714 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008715 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008716 if (axis == AXIS_ATTRIBUTE) {
8717 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008718#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008719 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008720#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008721 addNode(list, cur);
8722 }
8723 } else if (axis == AXIS_NAMESPACE) {
8724 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008725#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008726 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008727#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008728 xmlXPathNodeSetAddNs(list, ctxt->context->node,
8729 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008730 }
8731 } else {
8732 if (cur->type == XML_ELEMENT_NODE) {
8733 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008734#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008735 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008736#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008737 addNode(list, cur);
8738 } else if ((cur->ns != NULL) &&
8739 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008740#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008741 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008742#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008743 addNode(list, cur);
8744 }
8745 }
8746 }
8747 break;
8748 case NODE_TEST_NS:{
8749 TODO;
8750 break;
8751 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008752 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008753 switch (cur->type) {
8754 case XML_ELEMENT_NODE:
8755 if (xmlStrEqual(name, cur->name)) {
8756 if (prefix == NULL) {
8757 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008758#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008759 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008760#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008761 addNode(list, cur);
8762 }
8763 } else {
8764 if ((cur->ns != NULL) &&
8765 (xmlStrEqual(URI,
8766 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008767#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008768 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008769#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008770 addNode(list, cur);
8771 }
8772 }
8773 }
8774 break;
8775 case XML_ATTRIBUTE_NODE:{
8776 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008777
Daniel Veillardf06307e2001-07-03 10:35:50 +00008778 if (xmlStrEqual(name, attr->name)) {
8779 if (prefix == NULL) {
8780 if ((attr->ns == NULL) ||
8781 (attr->ns->prefix == NULL)) {
8782#ifdef DEBUG_STEP
8783 n++;
8784#endif
8785 addNode(list,
8786 (xmlNodePtr) attr);
8787 }
8788 } else {
8789 if ((attr->ns != NULL) &&
8790 (xmlStrEqual(URI,
8791 attr->ns->
8792 href))) {
8793#ifdef DEBUG_STEP
8794 n++;
8795#endif
8796 addNode(list,
8797 (xmlNodePtr) attr);
8798 }
8799 }
8800 }
8801 break;
8802 }
8803 case XML_NAMESPACE_DECL:
8804 if (cur->type == XML_NAMESPACE_DECL) {
8805 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008806
Daniel Veillardf06307e2001-07-03 10:35:50 +00008807 if ((ns->prefix != NULL) && (name != NULL)
8808 && (xmlStrEqual(ns->prefix, name))) {
8809#ifdef DEBUG_STEP
8810 n++;
8811#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008812 xmlXPathNodeSetAddNs(list,
8813 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008814 }
8815 }
8816 break;
8817 default:
8818 break;
8819 }
8820 break;
8821 break;
8822 }
8823 } while (cur != NULL);
8824
8825 /*
8826 * If there is some predicate filtering do it now
8827 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00008828 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008829 xmlXPathObjectPtr obj2;
8830
8831 valuePush(ctxt, xmlXPathWrapNodeSet(list));
8832 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
8833 CHECK_TYPE0(XPATH_NODESET);
8834 obj2 = valuePop(ctxt);
8835 list = obj2->nodesetval;
8836 obj2->nodesetval = NULL;
8837 xmlXPathFreeObject(obj2);
8838 }
8839 if (ret == NULL) {
8840 ret = list;
8841 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00008842 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008843 xmlXPathFreeNodeSet(list);
8844 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008845 }
8846 ctxt->context->node = tmp;
8847#ifdef DEBUG_STEP
8848 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008849 "\nExamined %d nodes, found %d nodes at that step\n",
8850 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008851#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008852 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00008853 if ((obj->boolval) && (obj->user != NULL)) {
8854 ctxt->value->boolval = 1;
8855 ctxt->value->user = obj->user;
8856 obj->user = NULL;
8857 obj->boolval = 0;
8858 }
8859 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008860 return(t);
8861}
8862
8863/**
8864 * xmlXPathNodeCollectAndTestNth:
8865 * @ctxt: the XPath Parser context
8866 * @op: the XPath precompiled step operation
8867 * @indx: the index to collect
8868 * @first: pointer to the first element in document order
8869 * @last: pointer to the last element in document order
8870 *
8871 * This is the function implementing a step: based on the current list
8872 * of nodes, it builds up a new list, looking at all nodes under that
8873 * axis and selecting them it also do the predicate filtering
8874 *
8875 * Pushes the new NodeSet resulting from the search.
8876 * Returns the number of node traversed
8877 */
8878static int
8879xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
8880 xmlXPathStepOpPtr op, int indx,
8881 xmlNodePtr * first, xmlNodePtr * last)
8882{
8883 xmlXPathAxisVal axis = op->value;
8884 xmlXPathTestVal test = op->value2;
8885 xmlXPathTypeVal type = op->value3;
8886 const xmlChar *prefix = op->value4;
8887 const xmlChar *name = op->value5;
8888 const xmlChar *URI = NULL;
8889 int n = 0, t = 0;
8890
8891 int i;
8892 xmlNodeSetPtr list;
8893 xmlXPathTraversalFunction next = NULL;
8894 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
8895 xmlNodePtr cur = NULL;
8896 xmlXPathObjectPtr obj;
8897 xmlNodeSetPtr nodelist;
8898 xmlNodePtr tmp;
8899
8900 CHECK_TYPE0(XPATH_NODESET);
8901 obj = valuePop(ctxt);
8902 addNode = xmlXPathNodeSetAdd;
8903 if (prefix != NULL) {
8904 URI = xmlXPathNsLookup(ctxt->context, prefix);
8905 if (URI == NULL)
8906 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8907 }
8908#ifdef DEBUG_STEP_NTH
8909 xmlGenericError(xmlGenericErrorContext, "new step : ");
8910 if (first != NULL) {
8911 if (*first != NULL)
8912 xmlGenericError(xmlGenericErrorContext, "first = %s ",
8913 (*first)->name);
8914 else
8915 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
8916 }
8917 if (last != NULL) {
8918 if (*last != NULL)
8919 xmlGenericError(xmlGenericErrorContext, "last = %s ",
8920 (*last)->name);
8921 else
8922 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
8923 }
8924#endif
8925 switch (axis) {
8926 case AXIS_ANCESTOR:
8927#ifdef DEBUG_STEP_NTH
8928 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
8929#endif
8930 first = NULL;
8931 next = xmlXPathNextAncestor;
8932 break;
8933 case AXIS_ANCESTOR_OR_SELF:
8934#ifdef DEBUG_STEP_NTH
8935 xmlGenericError(xmlGenericErrorContext,
8936 "axis 'ancestors-or-self' ");
8937#endif
8938 first = NULL;
8939 next = xmlXPathNextAncestorOrSelf;
8940 break;
8941 case AXIS_ATTRIBUTE:
8942#ifdef DEBUG_STEP_NTH
8943 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
8944#endif
8945 first = NULL;
8946 last = NULL;
8947 next = xmlXPathNextAttribute;
8948 break;
8949 case AXIS_CHILD:
8950#ifdef DEBUG_STEP_NTH
8951 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
8952#endif
8953 last = NULL;
8954 next = xmlXPathNextChild;
8955 break;
8956 case AXIS_DESCENDANT:
8957#ifdef DEBUG_STEP_NTH
8958 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
8959#endif
8960 last = NULL;
8961 next = xmlXPathNextDescendant;
8962 break;
8963 case AXIS_DESCENDANT_OR_SELF:
8964#ifdef DEBUG_STEP_NTH
8965 xmlGenericError(xmlGenericErrorContext,
8966 "axis 'descendant-or-self' ");
8967#endif
8968 last = NULL;
8969 next = xmlXPathNextDescendantOrSelf;
8970 break;
8971 case AXIS_FOLLOWING:
8972#ifdef DEBUG_STEP_NTH
8973 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
8974#endif
8975 last = NULL;
8976 next = xmlXPathNextFollowing;
8977 break;
8978 case AXIS_FOLLOWING_SIBLING:
8979#ifdef DEBUG_STEP_NTH
8980 xmlGenericError(xmlGenericErrorContext,
8981 "axis 'following-siblings' ");
8982#endif
8983 last = NULL;
8984 next = xmlXPathNextFollowingSibling;
8985 break;
8986 case AXIS_NAMESPACE:
8987#ifdef DEBUG_STEP_NTH
8988 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
8989#endif
8990 last = NULL;
8991 first = NULL;
8992 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
8993 break;
8994 case AXIS_PARENT:
8995#ifdef DEBUG_STEP_NTH
8996 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
8997#endif
8998 first = NULL;
8999 next = xmlXPathNextParent;
9000 break;
9001 case AXIS_PRECEDING:
9002#ifdef DEBUG_STEP_NTH
9003 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9004#endif
9005 first = NULL;
9006 next = xmlXPathNextPrecedingInternal;
9007 break;
9008 case AXIS_PRECEDING_SIBLING:
9009#ifdef DEBUG_STEP_NTH
9010 xmlGenericError(xmlGenericErrorContext,
9011 "axis 'preceding-sibling' ");
9012#endif
9013 first = NULL;
9014 next = xmlXPathNextPrecedingSibling;
9015 break;
9016 case AXIS_SELF:
9017#ifdef DEBUG_STEP_NTH
9018 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9019#endif
9020 first = NULL;
9021 last = NULL;
9022 next = xmlXPathNextSelf;
9023 break;
9024 }
9025 if (next == NULL)
9026 return(0);
9027
9028 nodelist = obj->nodesetval;
9029 if (nodelist == NULL) {
9030 xmlXPathFreeObject(obj);
9031 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9032 return(0);
9033 }
9034 addNode = xmlXPathNodeSetAddUnique;
9035#ifdef DEBUG_STEP_NTH
9036 xmlGenericError(xmlGenericErrorContext,
9037 " context contains %d nodes\n", nodelist->nodeNr);
9038 switch (test) {
9039 case NODE_TEST_NONE:
9040 xmlGenericError(xmlGenericErrorContext,
9041 " searching for none !!!\n");
9042 break;
9043 case NODE_TEST_TYPE:
9044 xmlGenericError(xmlGenericErrorContext,
9045 " searching for type %d\n", type);
9046 break;
9047 case NODE_TEST_PI:
9048 xmlGenericError(xmlGenericErrorContext,
9049 " searching for PI !!!\n");
9050 break;
9051 case NODE_TEST_ALL:
9052 xmlGenericError(xmlGenericErrorContext,
9053 " searching for *\n");
9054 break;
9055 case NODE_TEST_NS:
9056 xmlGenericError(xmlGenericErrorContext,
9057 " searching for namespace %s\n",
9058 prefix);
9059 break;
9060 case NODE_TEST_NAME:
9061 xmlGenericError(xmlGenericErrorContext,
9062 " searching for name %s\n", name);
9063 if (prefix != NULL)
9064 xmlGenericError(xmlGenericErrorContext,
9065 " with namespace %s\n", prefix);
9066 break;
9067 }
9068 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9069#endif
9070 /*
9071 * 2.3 Node Tests
9072 * - For the attribute axis, the principal node type is attribute.
9073 * - For the namespace axis, the principal node type is namespace.
9074 * - For other axes, the principal node type is element.
9075 *
9076 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009077 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009078 * select all element children of the context node
9079 */
9080 tmp = ctxt->context->node;
9081 list = xmlXPathNodeSetCreate(NULL);
9082 for (i = 0; i < nodelist->nodeNr; i++) {
9083 ctxt->context->node = nodelist->nodeTab[i];
9084
9085 cur = NULL;
9086 n = 0;
9087 do {
9088 cur = next(ctxt, cur);
9089 if (cur == NULL)
9090 break;
9091 if ((first != NULL) && (*first == cur))
9092 break;
9093 if (((t % 256) == 0) &&
9094 (first != NULL) && (*first != NULL) &&
9095 (xmlXPathCmpNodes(*first, cur) >= 0))
9096 break;
9097 if ((last != NULL) && (*last == cur))
9098 break;
9099 if (((t % 256) == 0) &&
9100 (last != NULL) && (*last != NULL) &&
9101 (xmlXPathCmpNodes(cur, *last) >= 0))
9102 break;
9103 t++;
9104 switch (test) {
9105 case NODE_TEST_NONE:
9106 ctxt->context->node = tmp;
9107 STRANGE return(0);
9108 case NODE_TEST_TYPE:
9109 if ((cur->type == type) ||
9110 ((type == NODE_TYPE_NODE) &&
9111 ((cur->type == XML_DOCUMENT_NODE) ||
9112 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9113 (cur->type == XML_ELEMENT_NODE) ||
9114 (cur->type == XML_PI_NODE) ||
9115 (cur->type == XML_COMMENT_NODE) ||
9116 (cur->type == XML_CDATA_SECTION_NODE) ||
9117 (cur->type == XML_TEXT_NODE)))) {
9118 n++;
9119 if (n == indx)
9120 addNode(list, cur);
9121 }
9122 break;
9123 case NODE_TEST_PI:
9124 if (cur->type == XML_PI_NODE) {
9125 if ((name != NULL) &&
9126 (!xmlStrEqual(name, cur->name)))
9127 break;
9128 n++;
9129 if (n == indx)
9130 addNode(list, cur);
9131 }
9132 break;
9133 case NODE_TEST_ALL:
9134 if (axis == AXIS_ATTRIBUTE) {
9135 if (cur->type == XML_ATTRIBUTE_NODE) {
9136 n++;
9137 if (n == indx)
9138 addNode(list, cur);
9139 }
9140 } else if (axis == AXIS_NAMESPACE) {
9141 if (cur->type == XML_NAMESPACE_DECL) {
9142 n++;
9143 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009144 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9145 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009146 }
9147 } else {
9148 if (cur->type == XML_ELEMENT_NODE) {
9149 if (prefix == NULL) {
9150 n++;
9151 if (n == indx)
9152 addNode(list, cur);
9153 } else if ((cur->ns != NULL) &&
9154 (xmlStrEqual(URI, cur->ns->href))) {
9155 n++;
9156 if (n == indx)
9157 addNode(list, cur);
9158 }
9159 }
9160 }
9161 break;
9162 case NODE_TEST_NS:{
9163 TODO;
9164 break;
9165 }
9166 case NODE_TEST_NAME:
9167 switch (cur->type) {
9168 case XML_ELEMENT_NODE:
9169 if (xmlStrEqual(name, cur->name)) {
9170 if (prefix == NULL) {
9171 if (cur->ns == NULL) {
9172 n++;
9173 if (n == indx)
9174 addNode(list, cur);
9175 }
9176 } else {
9177 if ((cur->ns != NULL) &&
9178 (xmlStrEqual(URI,
9179 cur->ns->href))) {
9180 n++;
9181 if (n == indx)
9182 addNode(list, cur);
9183 }
9184 }
9185 }
9186 break;
9187 case XML_ATTRIBUTE_NODE:{
9188 xmlAttrPtr attr = (xmlAttrPtr) cur;
9189
9190 if (xmlStrEqual(name, attr->name)) {
9191 if (prefix == NULL) {
9192 if ((attr->ns == NULL) ||
9193 (attr->ns->prefix == NULL)) {
9194 n++;
9195 if (n == indx)
9196 addNode(list, cur);
9197 }
9198 } else {
9199 if ((attr->ns != NULL) &&
9200 (xmlStrEqual(URI,
9201 attr->ns->
9202 href))) {
9203 n++;
9204 if (n == indx)
9205 addNode(list, cur);
9206 }
9207 }
9208 }
9209 break;
9210 }
9211 case XML_NAMESPACE_DECL:
9212 if (cur->type == XML_NAMESPACE_DECL) {
9213 xmlNsPtr ns = (xmlNsPtr) cur;
9214
9215 if ((ns->prefix != NULL) && (name != NULL)
9216 && (xmlStrEqual(ns->prefix, name))) {
9217 n++;
9218 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009219 xmlXPathNodeSetAddNs(list,
9220 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009221 }
9222 }
9223 break;
9224 default:
9225 break;
9226 }
9227 break;
9228 break;
9229 }
9230 } while (n < indx);
9231 }
9232 ctxt->context->node = tmp;
9233#ifdef DEBUG_STEP_NTH
9234 xmlGenericError(xmlGenericErrorContext,
9235 "\nExamined %d nodes, found %d nodes at that step\n",
9236 t, list->nodeNr);
9237#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009238 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009239 if ((obj->boolval) && (obj->user != NULL)) {
9240 ctxt->value->boolval = 1;
9241 ctxt->value->user = obj->user;
9242 obj->user = NULL;
9243 obj->boolval = 0;
9244 }
9245 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009246 return(t);
9247}
9248
9249/**
9250 * xmlXPathCompOpEvalFirst:
9251 * @ctxt: the XPath parser context with the compiled expression
9252 * @op: an XPath compiled operation
9253 * @first: the first elem found so far
9254 *
9255 * Evaluate the Precompiled XPath operation searching only the first
9256 * element in document order
9257 *
9258 * Returns the number of examined objects.
9259 */
9260static int
9261xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9262 xmlXPathStepOpPtr op, xmlNodePtr * first)
9263{
9264 int total = 0, cur;
9265 xmlXPathCompExprPtr comp;
9266 xmlXPathObjectPtr arg1, arg2;
9267
Daniel Veillard556c6682001-10-06 09:59:51 +00009268 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009269 comp = ctxt->comp;
9270 switch (op->op) {
9271 case XPATH_OP_END:
9272 return (0);
9273 case XPATH_OP_UNION:
9274 total =
9275 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9276 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009277 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009278 if ((ctxt->value != NULL)
9279 && (ctxt->value->type == XPATH_NODESET)
9280 && (ctxt->value->nodesetval != NULL)
9281 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9282 /*
9283 * limit tree traversing to first node in the result
9284 */
9285 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9286 *first = ctxt->value->nodesetval->nodeTab[0];
9287 }
9288 cur =
9289 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9290 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009291 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009292 CHECK_TYPE0(XPATH_NODESET);
9293 arg2 = valuePop(ctxt);
9294
9295 CHECK_TYPE0(XPATH_NODESET);
9296 arg1 = valuePop(ctxt);
9297
9298 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9299 arg2->nodesetval);
9300 valuePush(ctxt, arg1);
9301 xmlXPathFreeObject(arg2);
9302 /* optimizer */
9303 if (total > cur)
9304 xmlXPathCompSwap(op);
9305 return (total + cur);
9306 case XPATH_OP_ROOT:
9307 xmlXPathRoot(ctxt);
9308 return (0);
9309 case XPATH_OP_NODE:
9310 if (op->ch1 != -1)
9311 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009312 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009313 if (op->ch2 != -1)
9314 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009315 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009316 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9317 return (total);
9318 case XPATH_OP_RESET:
9319 if (op->ch1 != -1)
9320 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009321 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009322 if (op->ch2 != -1)
9323 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009324 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009325 ctxt->context->node = NULL;
9326 return (total);
9327 case XPATH_OP_COLLECT:{
9328 if (op->ch1 == -1)
9329 return (total);
9330
9331 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009332 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009333
9334 /*
9335 * Optimization for [n] selection where n is a number
9336 */
9337 if ((op->ch2 != -1) &&
9338 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9339 (comp->steps[op->ch2].ch1 == -1) &&
9340 (comp->steps[op->ch2].ch2 != -1) &&
9341 (comp->steps[comp->steps[op->ch2].ch2].op ==
9342 XPATH_OP_VALUE)) {
9343 xmlXPathObjectPtr val;
9344
9345 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9346 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9347 int indx = (int) val->floatval;
9348
9349 if (val->floatval == (float) indx) {
9350 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9351 first, NULL);
9352 return (total);
9353 }
9354 }
9355 }
9356 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9357 return (total);
9358 }
9359 case XPATH_OP_VALUE:
9360 valuePush(ctxt,
9361 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9362 return (0);
9363 case XPATH_OP_SORT:
9364 if (op->ch1 != -1)
9365 total +=
9366 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9367 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009368 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009369 if ((ctxt->value != NULL)
9370 && (ctxt->value->type == XPATH_NODESET)
9371 && (ctxt->value->nodesetval != NULL))
9372 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9373 return (total);
9374 default:
9375 return (xmlXPathCompOpEval(ctxt, op));
9376 }
9377}
9378
9379/**
9380 * xmlXPathCompOpEvalLast:
9381 * @ctxt: the XPath parser context with the compiled expression
9382 * @op: an XPath compiled operation
9383 * @last: the last elem found so far
9384 *
9385 * Evaluate the Precompiled XPath operation searching only the last
9386 * element in document order
9387 *
9388 * Returns the number of node traversed
9389 */
9390static int
9391xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9392 xmlNodePtr * last)
9393{
9394 int total = 0, cur;
9395 xmlXPathCompExprPtr comp;
9396 xmlXPathObjectPtr arg1, arg2;
9397
Daniel Veillard556c6682001-10-06 09:59:51 +00009398 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009399 comp = ctxt->comp;
9400 switch (op->op) {
9401 case XPATH_OP_END:
9402 return (0);
9403 case XPATH_OP_UNION:
9404 total =
9405 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009406 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009407 if ((ctxt->value != NULL)
9408 && (ctxt->value->type == XPATH_NODESET)
9409 && (ctxt->value->nodesetval != NULL)
9410 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9411 /*
9412 * limit tree traversing to first node in the result
9413 */
9414 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9415 *last =
9416 ctxt->value->nodesetval->nodeTab[ctxt->value->
9417 nodesetval->nodeNr -
9418 1];
9419 }
9420 cur =
9421 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009422 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009423 if ((ctxt->value != NULL)
9424 && (ctxt->value->type == XPATH_NODESET)
9425 && (ctxt->value->nodesetval != NULL)
9426 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9427 }
9428 CHECK_TYPE0(XPATH_NODESET);
9429 arg2 = valuePop(ctxt);
9430
9431 CHECK_TYPE0(XPATH_NODESET);
9432 arg1 = valuePop(ctxt);
9433
9434 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9435 arg2->nodesetval);
9436 valuePush(ctxt, arg1);
9437 xmlXPathFreeObject(arg2);
9438 /* optimizer */
9439 if (total > cur)
9440 xmlXPathCompSwap(op);
9441 return (total + cur);
9442 case XPATH_OP_ROOT:
9443 xmlXPathRoot(ctxt);
9444 return (0);
9445 case XPATH_OP_NODE:
9446 if (op->ch1 != -1)
9447 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009448 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009449 if (op->ch2 != -1)
9450 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009451 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009452 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9453 return (total);
9454 case XPATH_OP_RESET:
9455 if (op->ch1 != -1)
9456 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009457 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009458 if (op->ch2 != -1)
9459 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009460 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009461 ctxt->context->node = NULL;
9462 return (total);
9463 case XPATH_OP_COLLECT:{
9464 if (op->ch1 == -1)
9465 return (0);
9466
9467 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009468 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009469
9470 /*
9471 * Optimization for [n] selection where n is a number
9472 */
9473 if ((op->ch2 != -1) &&
9474 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9475 (comp->steps[op->ch2].ch1 == -1) &&
9476 (comp->steps[op->ch2].ch2 != -1) &&
9477 (comp->steps[comp->steps[op->ch2].ch2].op ==
9478 XPATH_OP_VALUE)) {
9479 xmlXPathObjectPtr val;
9480
9481 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9482 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9483 int indx = (int) val->floatval;
9484
9485 if (val->floatval == (float) indx) {
9486 total +=
9487 xmlXPathNodeCollectAndTestNth(ctxt, op,
9488 indx, NULL,
9489 last);
9490 return (total);
9491 }
9492 }
9493 }
9494 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9495 return (total);
9496 }
9497 case XPATH_OP_VALUE:
9498 valuePush(ctxt,
9499 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9500 return (0);
9501 case XPATH_OP_SORT:
9502 if (op->ch1 != -1)
9503 total +=
9504 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9505 last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009506 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009507 if ((ctxt->value != NULL)
9508 && (ctxt->value->type == XPATH_NODESET)
9509 && (ctxt->value->nodesetval != NULL))
9510 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9511 return (total);
9512 default:
9513 return (xmlXPathCompOpEval(ctxt, op));
9514 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009515}
9516
Owen Taylor3473f882001-02-23 17:55:21 +00009517/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009518 * xmlXPathCompOpEval:
9519 * @ctxt: the XPath parser context with the compiled expression
9520 * @op: an XPath compiled operation
9521 *
9522 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009523 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009524 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009525static int
9526xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9527{
9528 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009529 int equal, ret;
9530 xmlXPathCompExprPtr comp;
9531 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009532 xmlNodePtr bak;
9533 xmlDocPtr bakd;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009534
Daniel Veillard556c6682001-10-06 09:59:51 +00009535 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009536 comp = ctxt->comp;
9537 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009538 case XPATH_OP_END:
9539 return (0);
9540 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009541 bakd = ctxt->context->doc;
9542 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009543 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009544 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009545 xmlXPathBooleanFunction(ctxt, 1);
9546 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9547 return (total);
9548 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009549 ctxt->context->doc = bakd;
9550 ctxt->context->node = bak;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009551 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009552 if (ctxt->error) {
9553 xmlXPathFreeObject(arg2);
9554 return(0);
9555 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009556 xmlXPathBooleanFunction(ctxt, 1);
9557 arg1 = valuePop(ctxt);
9558 arg1->boolval &= arg2->boolval;
9559 valuePush(ctxt, arg1);
9560 xmlXPathFreeObject(arg2);
9561 return (total);
9562 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009563 bakd = ctxt->context->doc;
9564 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009565 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009566 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009567 xmlXPathBooleanFunction(ctxt, 1);
9568 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9569 return (total);
9570 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009571 ctxt->context->doc = bakd;
9572 ctxt->context->node = bak;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009573 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009574 if (ctxt->error) {
9575 xmlXPathFreeObject(arg2);
9576 return(0);
9577 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009578 xmlXPathBooleanFunction(ctxt, 1);
9579 arg1 = valuePop(ctxt);
9580 arg1->boolval |= arg2->boolval;
9581 valuePush(ctxt, arg1);
9582 xmlXPathFreeObject(arg2);
9583 return (total);
9584 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009585 bakd = ctxt->context->doc;
9586 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009587 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009588 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009589 ctxt->context->doc = bakd;
9590 ctxt->context->node = bak;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009591 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009592 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009593 equal = xmlXPathEqualValues(ctxt);
9594 if (op->value)
9595 valuePush(ctxt, xmlXPathNewBoolean(equal));
9596 else
9597 valuePush(ctxt, xmlXPathNewBoolean(!equal));
9598 return (total);
9599 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009600 bakd = ctxt->context->doc;
9601 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009602 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009603 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009604 ctxt->context->doc = bakd;
9605 ctxt->context->node = bak;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009606 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009607 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009608 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
9609 valuePush(ctxt, xmlXPathNewBoolean(ret));
9610 return (total);
9611 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009612 bakd = ctxt->context->doc;
9613 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009614 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009615 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009616 if (op->ch2 != -1) {
9617 ctxt->context->doc = bakd;
9618 ctxt->context->node = bak;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009619 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009620 }
Daniel Veillard556c6682001-10-06 09:59:51 +00009621 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009622 if (op->value == 0)
9623 xmlXPathSubValues(ctxt);
9624 else if (op->value == 1)
9625 xmlXPathAddValues(ctxt);
9626 else if (op->value == 2)
9627 xmlXPathValueFlipSign(ctxt);
9628 else if (op->value == 3) {
9629 CAST_TO_NUMBER;
9630 CHECK_TYPE0(XPATH_NUMBER);
9631 }
9632 return (total);
9633 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009634 bakd = ctxt->context->doc;
9635 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009636 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009637 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009638 ctxt->context->doc = bakd;
9639 ctxt->context->node = bak;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009640 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009641 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009642 if (op->value == 0)
9643 xmlXPathMultValues(ctxt);
9644 else if (op->value == 1)
9645 xmlXPathDivValues(ctxt);
9646 else if (op->value == 2)
9647 xmlXPathModValues(ctxt);
9648 return (total);
9649 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009650 bakd = ctxt->context->doc;
9651 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009652 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009653 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009654 ctxt->context->doc = bakd;
9655 ctxt->context->node = bak;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009656 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009657 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009658 CHECK_TYPE0(XPATH_NODESET);
9659 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009660
Daniel Veillardf06307e2001-07-03 10:35:50 +00009661 CHECK_TYPE0(XPATH_NODESET);
9662 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009663
Daniel Veillardf06307e2001-07-03 10:35:50 +00009664 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9665 arg2->nodesetval);
9666 valuePush(ctxt, arg1);
9667 xmlXPathFreeObject(arg2);
9668 return (total);
9669 case XPATH_OP_ROOT:
9670 xmlXPathRoot(ctxt);
9671 return (total);
9672 case XPATH_OP_NODE:
9673 if (op->ch1 != -1)
9674 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009675 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009676 if (op->ch2 != -1)
9677 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009678 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009679 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9680 return (total);
9681 case XPATH_OP_RESET:
9682 if (op->ch1 != -1)
9683 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009684 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009685 if (op->ch2 != -1)
9686 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009687 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009688 ctxt->context->node = NULL;
9689 return (total);
9690 case XPATH_OP_COLLECT:{
9691 if (op->ch1 == -1)
9692 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009693
Daniel Veillardf06307e2001-07-03 10:35:50 +00009694 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009695 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009696
Daniel Veillardf06307e2001-07-03 10:35:50 +00009697 /*
9698 * Optimization for [n] selection where n is a number
9699 */
9700 if ((op->ch2 != -1) &&
9701 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9702 (comp->steps[op->ch2].ch1 == -1) &&
9703 (comp->steps[op->ch2].ch2 != -1) &&
9704 (comp->steps[comp->steps[op->ch2].ch2].op ==
9705 XPATH_OP_VALUE)) {
9706 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +00009707
Daniel Veillardf06307e2001-07-03 10:35:50 +00009708 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9709 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9710 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009711
Daniel Veillardf06307e2001-07-03 10:35:50 +00009712 if (val->floatval == (float) indx) {
9713 total +=
9714 xmlXPathNodeCollectAndTestNth(ctxt, op,
9715 indx, NULL,
9716 NULL);
9717 return (total);
9718 }
9719 }
9720 }
9721 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
9722 return (total);
9723 }
9724 case XPATH_OP_VALUE:
9725 valuePush(ctxt,
9726 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9727 return (total);
9728 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +00009729 xmlXPathObjectPtr val;
9730
Daniel Veillardf06307e2001-07-03 10:35:50 +00009731 if (op->ch1 != -1)
9732 total +=
9733 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009734 if (op->value5 == NULL) {
9735 val = xmlXPathVariableLookup(ctxt->context, op->value4);
9736 if (val == NULL) {
9737 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
9738 return(0);
9739 }
9740 valuePush(ctxt, val);
9741 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009742 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009743
Daniel Veillardf06307e2001-07-03 10:35:50 +00009744 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9745 if (URI == NULL) {
9746 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009747 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009748 op->value4, op->value5);
9749 return (total);
9750 }
Daniel Veillard556c6682001-10-06 09:59:51 +00009751 val = xmlXPathVariableLookupNS(ctxt->context,
9752 op->value4, URI);
9753 if (val == NULL) {
9754 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
9755 return(0);
9756 }
9757 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009758 }
9759 return (total);
9760 }
9761 case XPATH_OP_FUNCTION:{
9762 xmlXPathFunction func;
9763 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +00009764 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009765
9766 if (op->ch1 != -1)
9767 total +=
9768 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009769 if (ctxt->valueNr < op->value) {
9770 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009771 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +00009772 ctxt->error = XPATH_INVALID_OPERAND;
9773 return (total);
9774 }
9775 for (i = 0; i < op->value; i++)
9776 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
9777 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009778 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +00009779 ctxt->error = XPATH_INVALID_OPERAND;
9780 return (total);
9781 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009782 if (op->cache != NULL)
9783 func = (xmlXPathFunction) op->cache;
9784 else {
9785 const xmlChar *URI = NULL;
9786
9787 if (op->value5 == NULL)
9788 func =
9789 xmlXPathFunctionLookup(ctxt->context,
9790 op->value4);
9791 else {
9792 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9793 if (URI == NULL) {
9794 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009795 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009796 op->value4, op->value5);
9797 return (total);
9798 }
9799 func = xmlXPathFunctionLookupNS(ctxt->context,
9800 op->value4, URI);
9801 }
9802 if (func == NULL) {
9803 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009804 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009805 op->value4);
9806 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009807 }
9808 op->cache = (void *) func;
9809 op->cacheURI = (void *) URI;
9810 }
9811 oldFunc = ctxt->context->function;
9812 oldFuncURI = ctxt->context->functionURI;
9813 ctxt->context->function = op->value4;
9814 ctxt->context->functionURI = op->cacheURI;
9815 func(ctxt, op->value);
9816 ctxt->context->function = oldFunc;
9817 ctxt->context->functionURI = oldFuncURI;
9818 return (total);
9819 }
9820 case XPATH_OP_ARG:
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 return (total);
9828 case XPATH_OP_PREDICATE:
9829 case XPATH_OP_FILTER:{
9830 xmlXPathObjectPtr res;
9831 xmlXPathObjectPtr obj, tmp;
9832 xmlNodeSetPtr newset = NULL;
9833 xmlNodeSetPtr oldset;
9834 xmlNodePtr oldnode;
9835 int i;
9836
9837 /*
9838 * Optimization for ()[1] selection i.e. the first elem
9839 */
9840 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9841 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9842 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
9843 xmlXPathObjectPtr val;
9844
9845 val = comp->steps[op->ch2].value4;
9846 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
9847 (val->floatval == 1.0)) {
9848 xmlNodePtr first = NULL;
9849
9850 total +=
9851 xmlXPathCompOpEvalFirst(ctxt,
9852 &comp->steps[op->ch1],
9853 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009854 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009855 /*
9856 * The nodeset should be in document order,
9857 * Keep only the first value
9858 */
9859 if ((ctxt->value != NULL) &&
9860 (ctxt->value->type == XPATH_NODESET) &&
9861 (ctxt->value->nodesetval != NULL) &&
9862 (ctxt->value->nodesetval->nodeNr > 1))
9863 ctxt->value->nodesetval->nodeNr = 1;
9864 return (total);
9865 }
9866 }
9867 /*
9868 * Optimization for ()[last()] selection i.e. the last elem
9869 */
9870 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9871 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9872 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
9873 int f = comp->steps[op->ch2].ch1;
9874
9875 if ((f != -1) &&
9876 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
9877 (comp->steps[f].value5 == NULL) &&
9878 (comp->steps[f].value == 0) &&
9879 (comp->steps[f].value4 != NULL) &&
9880 (xmlStrEqual
9881 (comp->steps[f].value4, BAD_CAST "last"))) {
9882 xmlNodePtr last = NULL;
9883
9884 total +=
9885 xmlXPathCompOpEvalLast(ctxt,
9886 &comp->steps[op->ch1],
9887 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009888 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009889 /*
9890 * The nodeset should be in document order,
9891 * Keep only the last value
9892 */
9893 if ((ctxt->value != NULL) &&
9894 (ctxt->value->type == XPATH_NODESET) &&
9895 (ctxt->value->nodesetval != NULL) &&
9896 (ctxt->value->nodesetval->nodeTab != NULL) &&
9897 (ctxt->value->nodesetval->nodeNr > 1)) {
9898 ctxt->value->nodesetval->nodeTab[0] =
9899 ctxt->value->nodesetval->nodeTab[ctxt->
9900 value->
9901 nodesetval->
9902 nodeNr -
9903 1];
9904 ctxt->value->nodesetval->nodeNr = 1;
9905 }
9906 return (total);
9907 }
9908 }
9909
9910 if (op->ch1 != -1)
9911 total +=
9912 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009913 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009914 if (op->ch2 == -1)
9915 return (total);
9916 if (ctxt->value == NULL)
9917 return (total);
9918
9919 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009920
9921#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00009922 /*
9923 * Hum are we filtering the result of an XPointer expression
9924 */
9925 if (ctxt->value->type == XPATH_LOCATIONSET) {
9926 xmlLocationSetPtr newlocset = NULL;
9927 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009928
Daniel Veillardf06307e2001-07-03 10:35:50 +00009929 /*
9930 * Extract the old locset, and then evaluate the result of the
9931 * expression for all the element in the locset. use it to grow
9932 * up a new locset.
9933 */
9934 CHECK_TYPE0(XPATH_LOCATIONSET);
9935 obj = valuePop(ctxt);
9936 oldlocset = obj->user;
9937 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009938
Daniel Veillardf06307e2001-07-03 10:35:50 +00009939 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
9940 ctxt->context->contextSize = 0;
9941 ctxt->context->proximityPosition = 0;
9942 if (op->ch2 != -1)
9943 total +=
9944 xmlXPathCompOpEval(ctxt,
9945 &comp->steps[op->ch2]);
9946 res = valuePop(ctxt);
9947 if (res != NULL)
9948 xmlXPathFreeObject(res);
9949 valuePush(ctxt, obj);
9950 CHECK_ERROR0;
9951 return (total);
9952 }
9953 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009954
Daniel Veillardf06307e2001-07-03 10:35:50 +00009955 for (i = 0; i < oldlocset->locNr; i++) {
9956 /*
9957 * Run the evaluation with a node list made of a
9958 * single item in the nodelocset.
9959 */
9960 ctxt->context->node = oldlocset->locTab[i]->user;
9961 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9962 valuePush(ctxt, tmp);
9963 ctxt->context->contextSize = oldlocset->locNr;
9964 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009965
Daniel Veillardf06307e2001-07-03 10:35:50 +00009966 if (op->ch2 != -1)
9967 total +=
9968 xmlXPathCompOpEval(ctxt,
9969 &comp->steps[op->ch2]);
9970 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009971
Daniel Veillardf06307e2001-07-03 10:35:50 +00009972 /*
9973 * The result of the evaluation need to be tested to
9974 * decided whether the filter succeeded or not
9975 */
9976 res = valuePop(ctxt);
9977 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
9978 xmlXPtrLocationSetAdd(newlocset,
9979 xmlXPathObjectCopy
9980 (oldlocset->locTab[i]));
9981 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009982
Daniel Veillardf06307e2001-07-03 10:35:50 +00009983 /*
9984 * Cleanup
9985 */
9986 if (res != NULL)
9987 xmlXPathFreeObject(res);
9988 if (ctxt->value == tmp) {
9989 res = valuePop(ctxt);
9990 xmlXPathFreeObject(res);
9991 }
9992
9993 ctxt->context->node = NULL;
9994 }
9995
9996 /*
9997 * The result is used as the new evaluation locset.
9998 */
9999 xmlXPathFreeObject(obj);
10000 ctxt->context->node = NULL;
10001 ctxt->context->contextSize = -1;
10002 ctxt->context->proximityPosition = -1;
10003 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10004 ctxt->context->node = oldnode;
10005 return (total);
10006 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010007#endif /* LIBXML_XPTR_ENABLED */
10008
Daniel Veillardf06307e2001-07-03 10:35:50 +000010009 /*
10010 * Extract the old set, and then evaluate the result of the
10011 * expression for all the element in the set. use it to grow
10012 * up a new set.
10013 */
10014 CHECK_TYPE0(XPATH_NODESET);
10015 obj = valuePop(ctxt);
10016 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010017
Daniel Veillardf06307e2001-07-03 10:35:50 +000010018 oldnode = ctxt->context->node;
10019 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010020
Daniel Veillardf06307e2001-07-03 10:35:50 +000010021 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10022 ctxt->context->contextSize = 0;
10023 ctxt->context->proximityPosition = 0;
10024 if (op->ch2 != -1)
10025 total +=
10026 xmlXPathCompOpEval(ctxt,
10027 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010028 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010029 res = valuePop(ctxt);
10030 if (res != NULL)
10031 xmlXPathFreeObject(res);
10032 valuePush(ctxt, obj);
10033 ctxt->context->node = oldnode;
10034 CHECK_ERROR0;
10035 } else {
10036 /*
10037 * Initialize the new set.
10038 */
10039 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010040
Daniel Veillardf06307e2001-07-03 10:35:50 +000010041 for (i = 0; i < oldset->nodeNr; i++) {
10042 /*
10043 * Run the evaluation with a node list made of
10044 * a single item in the nodeset.
10045 */
10046 ctxt->context->node = oldset->nodeTab[i];
10047 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10048 valuePush(ctxt, tmp);
10049 ctxt->context->contextSize = oldset->nodeNr;
10050 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010051
Daniel Veillardf06307e2001-07-03 10:35:50 +000010052 if (op->ch2 != -1)
10053 total +=
10054 xmlXPathCompOpEval(ctxt,
10055 &comp->steps[op->ch2]);
10056 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010057
Daniel Veillardf06307e2001-07-03 10:35:50 +000010058 /*
10059 * The result of the evaluation need to be tested to
10060 * decided whether the filter succeeded or not
10061 */
10062 res = valuePop(ctxt);
10063 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10064 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10065 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010066
Daniel Veillardf06307e2001-07-03 10:35:50 +000010067 /*
10068 * Cleanup
10069 */
10070 if (res != NULL)
10071 xmlXPathFreeObject(res);
10072 if (ctxt->value == tmp) {
10073 res = valuePop(ctxt);
10074 xmlXPathFreeObject(res);
10075 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010076
Daniel Veillardf06307e2001-07-03 10:35:50 +000010077 ctxt->context->node = NULL;
10078 }
10079
10080 /*
10081 * The result is used as the new evaluation set.
10082 */
10083 xmlXPathFreeObject(obj);
10084 ctxt->context->node = NULL;
10085 ctxt->context->contextSize = -1;
10086 ctxt->context->proximityPosition = -1;
10087 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10088 }
10089 ctxt->context->node = oldnode;
10090 return (total);
10091 }
10092 case XPATH_OP_SORT:
10093 if (op->ch1 != -1)
10094 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010095 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010096 if ((ctxt->value != NULL) &&
10097 (ctxt->value->type == XPATH_NODESET) &&
10098 (ctxt->value->nodesetval != NULL))
10099 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10100 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010101#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010102 case XPATH_OP_RANGETO:{
10103 xmlXPathObjectPtr range;
10104 xmlXPathObjectPtr res, obj;
10105 xmlXPathObjectPtr tmp;
10106 xmlLocationSetPtr newset = NULL;
10107 xmlNodeSetPtr oldset;
10108 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010109
Daniel Veillardf06307e2001-07-03 10:35:50 +000010110 if (op->ch1 != -1)
10111 total +=
10112 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10113 if (op->ch2 == -1)
10114 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010115
Daniel Veillardf06307e2001-07-03 10:35:50 +000010116 CHECK_TYPE0(XPATH_NODESET);
10117 obj = valuePop(ctxt);
10118 oldset = obj->nodesetval;
10119 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010120
Daniel Veillardf06307e2001-07-03 10:35:50 +000010121 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010122
Daniel Veillardf06307e2001-07-03 10:35:50 +000010123 if (oldset != NULL) {
10124 for (i = 0; i < oldset->nodeNr; i++) {
10125 /*
10126 * Run the evaluation with a node list made of a single item
10127 * in the nodeset.
10128 */
10129 ctxt->context->node = oldset->nodeTab[i];
10130 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10131 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010132
Daniel Veillardf06307e2001-07-03 10:35:50 +000010133 if (op->ch2 != -1)
10134 total +=
10135 xmlXPathCompOpEval(ctxt,
10136 &comp->steps[op->ch2]);
10137 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010138
Daniel Veillardf06307e2001-07-03 10:35:50 +000010139 /*
10140 * The result of the evaluation need to be tested to
10141 * decided whether the filter succeeded or not
10142 */
10143 res = valuePop(ctxt);
10144 range =
10145 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10146 res);
10147 if (range != NULL) {
10148 xmlXPtrLocationSetAdd(newset, range);
10149 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010150
Daniel Veillardf06307e2001-07-03 10:35:50 +000010151 /*
10152 * Cleanup
10153 */
10154 if (res != NULL)
10155 xmlXPathFreeObject(res);
10156 if (ctxt->value == tmp) {
10157 res = valuePop(ctxt);
10158 xmlXPathFreeObject(res);
10159 }
10160
10161 ctxt->context->node = NULL;
10162 }
10163 }
10164
10165 /*
10166 * The result is used as the new evaluation set.
10167 */
10168 xmlXPathFreeObject(obj);
10169 ctxt->context->node = NULL;
10170 ctxt->context->contextSize = -1;
10171 ctxt->context->proximityPosition = -1;
10172 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
10173 return (total);
10174 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010175#endif /* LIBXML_XPTR_ENABLED */
10176 }
10177 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010178 "XPath: unknown precompiled operation %d\n", op->op);
10179 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010180}
10181
10182/**
10183 * xmlXPathRunEval:
10184 * @ctxt: the XPath parser context with the compiled expression
10185 *
10186 * Evaluate the Precompiled XPath expression in the given context.
10187 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010188static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010189xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10190 xmlXPathCompExprPtr comp;
10191
10192 if ((ctxt == NULL) || (ctxt->comp == NULL))
10193 return;
10194
10195 if (ctxt->valueTab == NULL) {
10196 /* Allocate the value stack */
10197 ctxt->valueTab = (xmlXPathObjectPtr *)
10198 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10199 if (ctxt->valueTab == NULL) {
10200 xmlFree(ctxt);
10201 xmlGenericError(xmlGenericErrorContext,
10202 "xmlXPathRunEval: out of memory\n");
10203 return;
10204 }
10205 ctxt->valueNr = 0;
10206 ctxt->valueMax = 10;
10207 ctxt->value = NULL;
10208 }
10209 comp = ctxt->comp;
10210 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10211}
10212
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010213/************************************************************************
10214 * *
10215 * Public interfaces *
10216 * *
10217 ************************************************************************/
10218
10219/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010220 * xmlXPathEvalPredicate:
10221 * @ctxt: the XPath context
10222 * @res: the Predicate Expression evaluation result
10223 *
10224 * Evaluate a predicate result for the current node.
10225 * A PredicateExpr is evaluated by evaluating the Expr and converting
10226 * the result to a boolean. If the result is a number, the result will
10227 * be converted to true if the number is equal to the position of the
10228 * context node in the context node list (as returned by the position
10229 * function) and will be converted to false otherwise; if the result
10230 * is not a number, then the result will be converted as if by a call
10231 * to the boolean function.
10232 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010233 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010234 */
10235int
10236xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
10237 if (res == NULL) return(0);
10238 switch (res->type) {
10239 case XPATH_BOOLEAN:
10240 return(res->boolval);
10241 case XPATH_NUMBER:
10242 return(res->floatval == ctxt->proximityPosition);
10243 case XPATH_NODESET:
10244 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010245 if (res->nodesetval == NULL)
10246 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010247 return(res->nodesetval->nodeNr != 0);
10248 case XPATH_STRING:
10249 return((res->stringval != NULL) &&
10250 (xmlStrlen(res->stringval) != 0));
10251 default:
10252 STRANGE
10253 }
10254 return(0);
10255}
10256
10257/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010258 * xmlXPathEvaluatePredicateResult:
10259 * @ctxt: the XPath Parser context
10260 * @res: the Predicate Expression evaluation result
10261 *
10262 * Evaluate a predicate result for the current node.
10263 * A PredicateExpr is evaluated by evaluating the Expr and converting
10264 * the result to a boolean. If the result is a number, the result will
10265 * be converted to true if the number is equal to the position of the
10266 * context node in the context node list (as returned by the position
10267 * function) and will be converted to false otherwise; if the result
10268 * is not a number, then the result will be converted as if by a call
10269 * to the boolean function.
10270 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010271 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010272 */
10273int
10274xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10275 xmlXPathObjectPtr res) {
10276 if (res == NULL) return(0);
10277 switch (res->type) {
10278 case XPATH_BOOLEAN:
10279 return(res->boolval);
10280 case XPATH_NUMBER:
10281 return(res->floatval == ctxt->context->proximityPosition);
10282 case XPATH_NODESET:
10283 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000010284 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000010285 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010286 return(res->nodesetval->nodeNr != 0);
10287 case XPATH_STRING:
10288 return((res->stringval != NULL) &&
10289 (xmlStrlen(res->stringval) != 0));
10290 default:
10291 STRANGE
10292 }
10293 return(0);
10294}
10295
10296/**
10297 * xmlXPathCompile:
10298 * @str: the XPath expression
10299 *
10300 * Compile an XPath expression
10301 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010302 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010303 * the caller has to free the object.
10304 */
10305xmlXPathCompExprPtr
10306xmlXPathCompile(const xmlChar *str) {
10307 xmlXPathParserContextPtr ctxt;
10308 xmlXPathCompExprPtr comp;
10309
10310 xmlXPathInit();
10311
10312 ctxt = xmlXPathNewParserContext(str, NULL);
10313 xmlXPathCompileExpr(ctxt);
10314
Daniel Veillard40af6492001-04-22 08:50:55 +000010315 if (*ctxt->cur != 0) {
10316 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10317 comp = NULL;
10318 } else {
10319 comp = ctxt->comp;
10320 ctxt->comp = NULL;
10321 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010322 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010323#ifdef DEBUG_EVAL_COUNTS
10324 if (comp != NULL) {
10325 comp->string = xmlStrdup(str);
10326 comp->nb = 0;
10327 }
10328#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010329 return(comp);
10330}
10331
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010332/**
10333 * xmlXPathCompiledEval:
10334 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000010335 * @ctx: the XPath context
10336 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010337 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000010338 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010339 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000010340 * the caller has to free the object.
10341 */
10342xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010343xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000010344 xmlXPathParserContextPtr ctxt;
10345 xmlXPathObjectPtr res, tmp, init = NULL;
10346 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000010347#ifndef LIBXML_THREAD_ENABLED
10348 static int reentance = 0;
10349#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010350
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010351 if ((comp == NULL) || (ctx == NULL))
10352 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010353 xmlXPathInit();
10354
10355 CHECK_CONTEXT(ctx)
10356
Daniel Veillard81463942001-10-16 12:34:39 +000010357#ifndef LIBXML_THREAD_ENABLED
10358 reentance++;
10359 if (reentance > 1)
10360 xmlXPathDisableOptimizer = 1;
10361#endif
10362
Daniel Veillardf06307e2001-07-03 10:35:50 +000010363#ifdef DEBUG_EVAL_COUNTS
10364 comp->nb++;
10365 if ((comp->string != NULL) && (comp->nb > 100)) {
10366 fprintf(stderr, "100 x %s\n", comp->string);
10367 comp->nb = 0;
10368 }
10369#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010370 ctxt = xmlXPathCompParserContext(comp, ctx);
10371 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010372
10373 if (ctxt->value == NULL) {
10374 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010375 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000010376 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000010377 } else {
10378 res = valuePop(ctxt);
10379 }
10380
Daniel Veillardf06307e2001-07-03 10:35:50 +000010381
Owen Taylor3473f882001-02-23 17:55:21 +000010382 do {
10383 tmp = valuePop(ctxt);
10384 if (tmp != NULL) {
10385 if (tmp != init)
10386 stack++;
10387 xmlXPathFreeObject(tmp);
10388 }
10389 } while (tmp != NULL);
10390 if ((stack != 0) && (res != NULL)) {
10391 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010392 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000010393 stack);
10394 }
10395 if (ctxt->error != XPATH_EXPRESSION_OK) {
10396 xmlXPathFreeObject(res);
10397 res = NULL;
10398 }
10399
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010400
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010401 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010402 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000010403#ifndef LIBXML_THREAD_ENABLED
10404 reentance--;
10405#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010406 return(res);
10407}
10408
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010409/**
10410 * xmlXPathEvalExpr:
10411 * @ctxt: the XPath Parser context
10412 *
10413 * Parse and evaluate an XPath expression in the given context,
10414 * then push the result on the context stack
10415 */
10416void
10417xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
10418 xmlXPathCompileExpr(ctxt);
10419 xmlXPathRunEval(ctxt);
10420}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010421
10422/**
10423 * xmlXPathEval:
10424 * @str: the XPath expression
10425 * @ctx: the XPath context
10426 *
10427 * Evaluate the XPath Location Path in the given context.
10428 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010429 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010430 * the caller has to free the object.
10431 */
10432xmlXPathObjectPtr
10433xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
10434 xmlXPathParserContextPtr ctxt;
10435 xmlXPathObjectPtr res, tmp, init = NULL;
10436 int stack = 0;
10437
10438 xmlXPathInit();
10439
10440 CHECK_CONTEXT(ctx)
10441
10442 ctxt = xmlXPathNewParserContext(str, ctx);
10443 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010444
10445 if (ctxt->value == NULL) {
10446 xmlGenericError(xmlGenericErrorContext,
10447 "xmlXPathEval: evaluation failed\n");
10448 res = NULL;
10449 } else if (*ctxt->cur != 0) {
10450 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10451 res = NULL;
10452 } else {
10453 res = valuePop(ctxt);
10454 }
10455
10456 do {
10457 tmp = valuePop(ctxt);
10458 if (tmp != NULL) {
10459 if (tmp != init)
10460 stack++;
10461 xmlXPathFreeObject(tmp);
10462 }
10463 } while (tmp != NULL);
10464 if ((stack != 0) && (res != NULL)) {
10465 xmlGenericError(xmlGenericErrorContext,
10466 "xmlXPathEval: %d object left on the stack\n",
10467 stack);
10468 }
10469 if (ctxt->error != XPATH_EXPRESSION_OK) {
10470 xmlXPathFreeObject(res);
10471 res = NULL;
10472 }
10473
Owen Taylor3473f882001-02-23 17:55:21 +000010474 xmlXPathFreeParserContext(ctxt);
10475 return(res);
10476}
10477
10478/**
10479 * xmlXPathEvalExpression:
10480 * @str: the XPath expression
10481 * @ctxt: the XPath context
10482 *
10483 * Evaluate the XPath expression in the given context.
10484 *
10485 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
10486 * the caller has to free the object.
10487 */
10488xmlXPathObjectPtr
10489xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
10490 xmlXPathParserContextPtr pctxt;
10491 xmlXPathObjectPtr res, tmp;
10492 int stack = 0;
10493
10494 xmlXPathInit();
10495
10496 CHECK_CONTEXT(ctxt)
10497
10498 pctxt = xmlXPathNewParserContext(str, ctxt);
10499 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010500
10501 if (*pctxt->cur != 0) {
10502 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10503 res = NULL;
10504 } else {
10505 res = valuePop(pctxt);
10506 }
10507 do {
10508 tmp = valuePop(pctxt);
10509 if (tmp != NULL) {
10510 xmlXPathFreeObject(tmp);
10511 stack++;
10512 }
10513 } while (tmp != NULL);
10514 if ((stack != 0) && (res != NULL)) {
10515 xmlGenericError(xmlGenericErrorContext,
10516 "xmlXPathEvalExpression: %d object left on the stack\n",
10517 stack);
10518 }
10519 xmlXPathFreeParserContext(pctxt);
10520 return(res);
10521}
10522
10523/**
10524 * xmlXPathRegisterAllFunctions:
10525 * @ctxt: the XPath context
10526 *
10527 * Registers all default XPath functions in this context
10528 */
10529void
10530xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
10531{
10532 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
10533 xmlXPathBooleanFunction);
10534 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
10535 xmlXPathCeilingFunction);
10536 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
10537 xmlXPathCountFunction);
10538 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
10539 xmlXPathConcatFunction);
10540 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
10541 xmlXPathContainsFunction);
10542 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
10543 xmlXPathIdFunction);
10544 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
10545 xmlXPathFalseFunction);
10546 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
10547 xmlXPathFloorFunction);
10548 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
10549 xmlXPathLastFunction);
10550 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
10551 xmlXPathLangFunction);
10552 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
10553 xmlXPathLocalNameFunction);
10554 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
10555 xmlXPathNotFunction);
10556 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
10557 xmlXPathNameFunction);
10558 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
10559 xmlXPathNamespaceURIFunction);
10560 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
10561 xmlXPathNormalizeFunction);
10562 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
10563 xmlXPathNumberFunction);
10564 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
10565 xmlXPathPositionFunction);
10566 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
10567 xmlXPathRoundFunction);
10568 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
10569 xmlXPathStringFunction);
10570 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
10571 xmlXPathStringLengthFunction);
10572 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
10573 xmlXPathStartsWithFunction);
10574 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
10575 xmlXPathSubstringFunction);
10576 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
10577 xmlXPathSubstringBeforeFunction);
10578 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
10579 xmlXPathSubstringAfterFunction);
10580 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
10581 xmlXPathSumFunction);
10582 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
10583 xmlXPathTrueFunction);
10584 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
10585 xmlXPathTranslateFunction);
10586}
10587
10588#endif /* LIBXML_XPATH_ENABLED */