blob: f8249896895e65b7ddce588a8e4aeb61816bf790 [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 Veillardda423da2002-04-10 19:25:38 +000073#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +000074/*
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 Veillardbc6f7592002-04-16 07:49:59 +0000395#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000396 /*
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"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001138 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001139 break;
1140 case -1:
1141 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001142 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001143 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"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001147 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001148 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001149 snprintf(buffer, buffersize, "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 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001492void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001493xmlXPathNodeSetFreeNs(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 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00001591void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001592xmlXPathNodeSetAddNs(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) {
Daniel Veillard23b1f372002-04-18 15:50:05 +00003219 if ((node != NULL) && (node->type == XML_DOCUMENT_NODE))
3220 node = xmlDocGetRootElement((xmlDocPtr) node);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003221 return(xmlNodeGetContent(node));
3222}
3223
3224/**
3225 * xmlXPathCastNodeSetToString:
3226 * @ns: a node-set
3227 *
3228 * Converts a node-set to its string value.
3229 *
3230 * Returns a newly allocated string.
3231 */
3232xmlChar *
3233xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3234 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3235 return(xmlStrdup((const xmlChar *) ""));
3236
3237 xmlXPathNodeSetSort(ns);
3238 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3239}
3240
3241/**
3242 * xmlXPathCastToString:
3243 * @val: an XPath object
3244 *
3245 * Converts an existing object to its string() equivalent
3246 *
3247 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003248 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003249 * string object).
3250 */
3251xmlChar *
3252xmlXPathCastToString(xmlXPathObjectPtr val) {
3253 xmlChar *ret = NULL;
3254
3255 if (val == NULL)
3256 return(xmlStrdup((const xmlChar *) ""));
3257 switch (val->type) {
3258 case XPATH_UNDEFINED:
3259#ifdef DEBUG_EXPR
3260 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3261#endif
3262 ret = xmlStrdup((const xmlChar *) "");
3263 break;
3264 case XPATH_XSLT_TREE:
3265 case XPATH_NODESET:
3266 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3267 break;
3268 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00003269 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003270 case XPATH_BOOLEAN:
3271 ret = xmlXPathCastBooleanToString(val->boolval);
3272 break;
3273 case XPATH_NUMBER: {
3274 ret = xmlXPathCastNumberToString(val->floatval);
3275 break;
3276 }
3277 case XPATH_USERS:
3278 case XPATH_POINT:
3279 case XPATH_RANGE:
3280 case XPATH_LOCATIONSET:
3281 TODO
3282 ret = xmlStrdup((const xmlChar *) "");
3283 break;
3284 }
3285 return(ret);
3286}
3287
3288/**
3289 * xmlXPathConvertString:
3290 * @val: an XPath object
3291 *
3292 * Converts an existing object to its string() equivalent
3293 *
3294 * Returns the new object, the old one is freed (or the operation
3295 * is done directly on @val)
3296 */
3297xmlXPathObjectPtr
3298xmlXPathConvertString(xmlXPathObjectPtr val) {
3299 xmlChar *res = NULL;
3300
3301 if (val == NULL)
3302 return(xmlXPathNewCString(""));
3303
3304 switch (val->type) {
3305 case XPATH_UNDEFINED:
3306#ifdef DEBUG_EXPR
3307 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3308#endif
3309 break;
3310 case XPATH_XSLT_TREE:
3311 case XPATH_NODESET:
3312 res = xmlXPathCastNodeSetToString(val->nodesetval);
3313 break;
3314 case XPATH_STRING:
3315 return(val);
3316 case XPATH_BOOLEAN:
3317 res = xmlXPathCastBooleanToString(val->boolval);
3318 break;
3319 case XPATH_NUMBER:
3320 res = xmlXPathCastNumberToString(val->floatval);
3321 break;
3322 case XPATH_USERS:
3323 case XPATH_POINT:
3324 case XPATH_RANGE:
3325 case XPATH_LOCATIONSET:
3326 TODO;
3327 break;
3328 }
3329 xmlXPathFreeObject(val);
3330 if (res == NULL)
3331 return(xmlXPathNewCString(""));
3332 return(xmlXPathWrapString(res));
3333}
3334
3335/**
3336 * xmlXPathCastBooleanToNumber:
3337 * @val: a boolean
3338 *
3339 * Converts a boolean to its number value
3340 *
3341 * Returns the number value
3342 */
3343double
3344xmlXPathCastBooleanToNumber(int val) {
3345 if (val)
3346 return(1.0);
3347 return(0.0);
3348}
3349
3350/**
3351 * xmlXPathCastStringToNumber:
3352 * @val: a string
3353 *
3354 * Converts a string to its number value
3355 *
3356 * Returns the number value
3357 */
3358double
3359xmlXPathCastStringToNumber(const xmlChar * val) {
3360 return(xmlXPathStringEvalNumber(val));
3361}
3362
3363/**
3364 * xmlXPathCastNodeToNumber:
3365 * @node: a node
3366 *
3367 * Converts a node to its number value
3368 *
3369 * Returns the number value
3370 */
3371double
3372xmlXPathCastNodeToNumber (xmlNodePtr node) {
3373 xmlChar *strval;
3374 double ret;
3375
3376 if (node == NULL)
3377 return(xmlXPathNAN);
3378 strval = xmlXPathCastNodeToString(node);
3379 if (strval == NULL)
3380 return(xmlXPathNAN);
3381 ret = xmlXPathCastStringToNumber(strval);
3382 xmlFree(strval);
3383
3384 return(ret);
3385}
3386
3387/**
3388 * xmlXPathCastNodeSetToNumber:
3389 * @ns: a node-set
3390 *
3391 * Converts a node-set to its number value
3392 *
3393 * Returns the number value
3394 */
3395double
3396xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3397 xmlChar *str;
3398 double ret;
3399
3400 if (ns == NULL)
3401 return(xmlXPathNAN);
3402 str = xmlXPathCastNodeSetToString(ns);
3403 ret = xmlXPathCastStringToNumber(str);
3404 xmlFree(str);
3405 return(ret);
3406}
3407
3408/**
3409 * xmlXPathCastToNumber:
3410 * @val: an XPath object
3411 *
3412 * Converts an XPath object to its number value
3413 *
3414 * Returns the number value
3415 */
3416double
3417xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3418 double ret = 0.0;
3419
3420 if (val == NULL)
3421 return(xmlXPathNAN);
3422 switch (val->type) {
3423 case XPATH_UNDEFINED:
3424#ifdef DEGUB_EXPR
3425 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3426#endif
3427 ret = xmlXPathNAN;
3428 break;
3429 case XPATH_XSLT_TREE:
3430 case XPATH_NODESET:
3431 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3432 break;
3433 case XPATH_STRING:
3434 ret = xmlXPathCastStringToNumber(val->stringval);
3435 break;
3436 case XPATH_NUMBER:
3437 ret = val->floatval;
3438 break;
3439 case XPATH_BOOLEAN:
3440 ret = xmlXPathCastBooleanToNumber(val->boolval);
3441 break;
3442 case XPATH_USERS:
3443 case XPATH_POINT:
3444 case XPATH_RANGE:
3445 case XPATH_LOCATIONSET:
3446 TODO;
3447 ret = xmlXPathNAN;
3448 break;
3449 }
3450 return(ret);
3451}
3452
3453/**
3454 * xmlXPathConvertNumber:
3455 * @val: an XPath object
3456 *
3457 * Converts an existing object to its number() equivalent
3458 *
3459 * Returns the new object, the old one is freed (or the operation
3460 * is done directly on @val)
3461 */
3462xmlXPathObjectPtr
3463xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3464 xmlXPathObjectPtr ret;
3465
3466 if (val == NULL)
3467 return(xmlXPathNewFloat(0.0));
3468 if (val->type == XPATH_NUMBER)
3469 return(val);
3470 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3471 xmlXPathFreeObject(val);
3472 return(ret);
3473}
3474
3475/**
3476 * xmlXPathCastNumberToBoolean:
3477 * @val: a number
3478 *
3479 * Converts a number to its boolean value
3480 *
3481 * Returns the boolean value
3482 */
3483int
3484xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003485 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003486 return(0);
3487 return(1);
3488}
3489
3490/**
3491 * xmlXPathCastStringToBoolean:
3492 * @val: a string
3493 *
3494 * Converts a string to its boolean value
3495 *
3496 * Returns the boolean value
3497 */
3498int
3499xmlXPathCastStringToBoolean (const xmlChar *val) {
3500 if ((val == NULL) || (xmlStrlen(val) == 0))
3501 return(0);
3502 return(1);
3503}
3504
3505/**
3506 * xmlXPathCastNodeSetToBoolean:
3507 * @ns: a node-set
3508 *
3509 * Converts a node-set to its boolean value
3510 *
3511 * Returns the boolean value
3512 */
3513int
3514xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3515 if ((ns == NULL) || (ns->nodeNr == 0))
3516 return(0);
3517 return(1);
3518}
3519
3520/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003521 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003522 * @val: an XPath object
3523 *
3524 * Converts an XPath object to its boolean value
3525 *
3526 * Returns the boolean value
3527 */
3528int
3529xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3530 int ret = 0;
3531
3532 if (val == NULL)
3533 return(0);
3534 switch (val->type) {
3535 case XPATH_UNDEFINED:
3536#ifdef DEBUG_EXPR
3537 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3538#endif
3539 ret = 0;
3540 break;
3541 case XPATH_XSLT_TREE:
3542 case XPATH_NODESET:
3543 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3544 break;
3545 case XPATH_STRING:
3546 ret = xmlXPathCastStringToBoolean(val->stringval);
3547 break;
3548 case XPATH_NUMBER:
3549 ret = xmlXPathCastNumberToBoolean(val->floatval);
3550 break;
3551 case XPATH_BOOLEAN:
3552 ret = val->boolval;
3553 break;
3554 case XPATH_USERS:
3555 case XPATH_POINT:
3556 case XPATH_RANGE:
3557 case XPATH_LOCATIONSET:
3558 TODO;
3559 ret = 0;
3560 break;
3561 }
3562 return(ret);
3563}
3564
3565
3566/**
3567 * xmlXPathConvertBoolean:
3568 * @val: an XPath object
3569 *
3570 * Converts an existing object to its boolean() equivalent
3571 *
3572 * Returns the new object, the old one is freed (or the operation
3573 * is done directly on @val)
3574 */
3575xmlXPathObjectPtr
3576xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3577 xmlXPathObjectPtr ret;
3578
3579 if (val == NULL)
3580 return(xmlXPathNewBoolean(0));
3581 if (val->type == XPATH_BOOLEAN)
3582 return(val);
3583 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3584 xmlXPathFreeObject(val);
3585 return(ret);
3586}
3587
Owen Taylor3473f882001-02-23 17:55:21 +00003588/************************************************************************
3589 * *
3590 * Routines to handle XPath contexts *
3591 * *
3592 ************************************************************************/
3593
3594/**
3595 * xmlXPathNewContext:
3596 * @doc: the XML document
3597 *
3598 * Create a new xmlXPathContext
3599 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00003600 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00003601 */
3602xmlXPathContextPtr
3603xmlXPathNewContext(xmlDocPtr doc) {
3604 xmlXPathContextPtr ret;
3605
3606 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3607 if (ret == NULL) {
3608 xmlGenericError(xmlGenericErrorContext,
3609 "xmlXPathNewContext: out of memory\n");
3610 return(NULL);
3611 }
3612 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3613 ret->doc = doc;
3614 ret->node = NULL;
3615
3616 ret->varHash = NULL;
3617
3618 ret->nb_types = 0;
3619 ret->max_types = 0;
3620 ret->types = NULL;
3621
3622 ret->funcHash = xmlHashCreate(0);
3623
3624 ret->nb_axis = 0;
3625 ret->max_axis = 0;
3626 ret->axis = NULL;
3627
3628 ret->nsHash = NULL;
3629 ret->user = NULL;
3630
3631 ret->contextSize = -1;
3632 ret->proximityPosition = -1;
3633
3634 xmlXPathRegisterAllFunctions(ret);
3635
3636 return(ret);
3637}
3638
3639/**
3640 * xmlXPathFreeContext:
3641 * @ctxt: the context to free
3642 *
3643 * Free up an xmlXPathContext
3644 */
3645void
3646xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3647 xmlXPathRegisteredNsCleanup(ctxt);
3648 xmlXPathRegisteredFuncsCleanup(ctxt);
3649 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003650 xmlFree(ctxt);
3651}
3652
3653/************************************************************************
3654 * *
3655 * Routines to handle XPath parser contexts *
3656 * *
3657 ************************************************************************/
3658
3659#define CHECK_CTXT(ctxt) \
3660 if (ctxt == NULL) { \
3661 xmlGenericError(xmlGenericErrorContext, \
3662 "%s:%d Internal error: ctxt == NULL\n", \
3663 __FILE__, __LINE__); \
3664 } \
3665
3666
3667#define CHECK_CONTEXT(ctxt) \
3668 if (ctxt == NULL) { \
3669 xmlGenericError(xmlGenericErrorContext, \
3670 "%s:%d Internal error: no context\n", \
3671 __FILE__, __LINE__); \
3672 } \
3673 else if (ctxt->doc == NULL) { \
3674 xmlGenericError(xmlGenericErrorContext, \
3675 "%s:%d Internal error: no document\n", \
3676 __FILE__, __LINE__); \
3677 } \
3678 else if (ctxt->doc->children == NULL) { \
3679 xmlGenericError(xmlGenericErrorContext, \
3680 "%s:%d Internal error: document without root\n", \
3681 __FILE__, __LINE__); \
3682 } \
3683
3684
3685/**
3686 * xmlXPathNewParserContext:
3687 * @str: the XPath expression
3688 * @ctxt: the XPath context
3689 *
3690 * Create a new xmlXPathParserContext
3691 *
3692 * Returns the xmlXPathParserContext just allocated.
3693 */
3694xmlXPathParserContextPtr
3695xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3696 xmlXPathParserContextPtr ret;
3697
3698 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3699 if (ret == NULL) {
3700 xmlGenericError(xmlGenericErrorContext,
3701 "xmlXPathNewParserContext: out of memory\n");
3702 return(NULL);
3703 }
3704 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3705 ret->cur = ret->base = str;
3706 ret->context = ctxt;
3707
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003708 ret->comp = xmlXPathNewCompExpr();
3709 if (ret->comp == NULL) {
3710 xmlFree(ret->valueTab);
3711 xmlFree(ret);
3712 return(NULL);
3713 }
3714
3715 return(ret);
3716}
3717
3718/**
3719 * xmlXPathCompParserContext:
3720 * @comp: the XPath compiled expression
3721 * @ctxt: the XPath context
3722 *
3723 * Create a new xmlXPathParserContext when processing a compiled expression
3724 *
3725 * Returns the xmlXPathParserContext just allocated.
3726 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003727static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003728xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3729 xmlXPathParserContextPtr ret;
3730
3731 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3732 if (ret == NULL) {
3733 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003734 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003735 return(NULL);
3736 }
3737 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3738
Owen Taylor3473f882001-02-23 17:55:21 +00003739 /* Allocate the value stack */
3740 ret->valueTab = (xmlXPathObjectPtr *)
3741 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003742 if (ret->valueTab == NULL) {
3743 xmlFree(ret);
3744 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003745 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003746 return(NULL);
3747 }
Owen Taylor3473f882001-02-23 17:55:21 +00003748 ret->valueNr = 0;
3749 ret->valueMax = 10;
3750 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003751
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00003752 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003753 ret->comp = comp;
3754
Owen Taylor3473f882001-02-23 17:55:21 +00003755 return(ret);
3756}
3757
3758/**
3759 * xmlXPathFreeParserContext:
3760 * @ctxt: the context to free
3761 *
3762 * Free up an xmlXPathParserContext
3763 */
3764void
3765xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
3766 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003767 xmlFree(ctxt->valueTab);
3768 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003769 if (ctxt->comp)
3770 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00003771 xmlFree(ctxt);
3772}
3773
3774/************************************************************************
3775 * *
3776 * The implicit core function library *
3777 * *
3778 ************************************************************************/
3779
Owen Taylor3473f882001-02-23 17:55:21 +00003780/**
Daniel Veillardf06307e2001-07-03 10:35:50 +00003781 * xmlXPathNodeStringHash:
3782 * @node: a node pointer
3783 *
3784 * Function computing the beginning of the string value of the node,
3785 * used to speed up comparisons
3786 *
3787 * Returns an int usable as a hash
3788 */
3789static unsigned int
3790xmlXPathNodeValHash(xmlNodePtr node) {
3791 int len = 2;
3792 const xmlChar * string = NULL;
3793 xmlNodePtr tmp = NULL;
3794 unsigned int ret = 0;
3795
3796 if (node == NULL)
3797 return(0);
3798
3799
3800 switch (node->type) {
3801 case XML_COMMENT_NODE:
3802 case XML_PI_NODE:
3803 case XML_CDATA_SECTION_NODE:
3804 case XML_TEXT_NODE:
3805 string = node->content;
3806 if (string == NULL)
3807 return(0);
3808 if (string[0] == 0)
3809 return(0);
3810 return(((unsigned int) string[0]) +
3811 (((unsigned int) string[1]) << 8));
3812 case XML_NAMESPACE_DECL:
3813 string = ((xmlNsPtr)node)->href;
3814 if (string == NULL)
3815 return(0);
3816 if (string[0] == 0)
3817 return(0);
3818 return(((unsigned int) string[0]) +
3819 (((unsigned int) string[1]) << 8));
3820 case XML_ATTRIBUTE_NODE:
3821 tmp = ((xmlAttrPtr) node)->children;
3822 break;
3823 case XML_ELEMENT_NODE:
3824 tmp = node->children;
3825 break;
3826 default:
3827 return(0);
3828 }
3829 while (tmp != NULL) {
3830 switch (tmp->type) {
3831 case XML_COMMENT_NODE:
3832 case XML_PI_NODE:
3833 case XML_CDATA_SECTION_NODE:
3834 case XML_TEXT_NODE:
3835 string = tmp->content;
3836 break;
3837 case XML_NAMESPACE_DECL:
3838 string = ((xmlNsPtr)tmp)->href;
3839 break;
3840 default:
3841 break;
3842 }
3843 if ((string != NULL) && (string[0] != 0)) {
3844 if (string[0] == 0)
3845 return(0);
3846 if (len == 1) {
3847 return(ret + (((unsigned int) string[0]) << 8));
3848 }
3849 if (string[1] == 0) {
3850 len = 1;
3851 ret = (unsigned int) string[0];
3852 } else {
3853 return(((unsigned int) string[0]) +
3854 (((unsigned int) string[1]) << 8));
3855 }
3856 }
3857 /*
3858 * Skip to next node
3859 */
3860 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
3861 if (tmp->children->type != XML_ENTITY_DECL) {
3862 tmp = tmp->children;
3863 continue;
3864 }
3865 }
3866 if (tmp == node)
3867 break;
3868
3869 if (tmp->next != NULL) {
3870 tmp = tmp->next;
3871 continue;
3872 }
3873
3874 do {
3875 tmp = tmp->parent;
3876 if (tmp == NULL)
3877 break;
3878 if (tmp == node) {
3879 tmp = NULL;
3880 break;
3881 }
3882 if (tmp->next != NULL) {
3883 tmp = tmp->next;
3884 break;
3885 }
3886 } while (tmp != NULL);
3887 }
3888 return(ret);
3889}
3890
3891/**
3892 * xmlXPathStringHash:
3893 * @string: a string
3894 *
3895 * Function computing the beginning of the string value of the node,
3896 * used to speed up comparisons
3897 *
3898 * Returns an int usable as a hash
3899 */
3900static unsigned int
3901xmlXPathStringHash(const xmlChar * string) {
3902 if (string == NULL)
3903 return((unsigned int) 0);
3904 if (string[0] == 0)
3905 return(0);
3906 return(((unsigned int) string[0]) +
3907 (((unsigned int) string[1]) << 8));
3908}
3909
3910/**
Owen Taylor3473f882001-02-23 17:55:21 +00003911 * xmlXPathCompareNodeSetFloat:
3912 * @ctxt: the XPath Parser context
3913 * @inf: less than (1) or greater than (0)
3914 * @strict: is the comparison strict
3915 * @arg: the node set
3916 * @f: the value
3917 *
3918 * Implement the compare operation between a nodeset and a number
3919 * @ns < @val (1, 1, ...
3920 * @ns <= @val (1, 0, ...
3921 * @ns > @val (0, 1, ...
3922 * @ns >= @val (0, 0, ...
3923 *
3924 * If one object to be compared is a node-set and the other is a number,
3925 * then the comparison will be true if and only if there is a node in the
3926 * node-set such that the result of performing the comparison on the number
3927 * to be compared and on the result of converting the string-value of that
3928 * node to a number using the number function is true.
3929 *
3930 * Returns 0 or 1 depending on the results of the test.
3931 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003932static int
Owen Taylor3473f882001-02-23 17:55:21 +00003933xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
3934 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
3935 int i, ret = 0;
3936 xmlNodeSetPtr ns;
3937 xmlChar *str2;
3938
3939 if ((f == NULL) || (arg == NULL) ||
3940 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3941 xmlXPathFreeObject(arg);
3942 xmlXPathFreeObject(f);
3943 return(0);
3944 }
3945 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003946 if (ns != NULL) {
3947 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003948 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003949 if (str2 != NULL) {
3950 valuePush(ctxt,
3951 xmlXPathNewString(str2));
3952 xmlFree(str2);
3953 xmlXPathNumberFunction(ctxt, 1);
3954 valuePush(ctxt, xmlXPathObjectCopy(f));
3955 ret = xmlXPathCompareValues(ctxt, inf, strict);
3956 if (ret)
3957 break;
3958 }
3959 }
Owen Taylor3473f882001-02-23 17:55:21 +00003960 }
3961 xmlXPathFreeObject(arg);
3962 xmlXPathFreeObject(f);
3963 return(ret);
3964}
3965
3966/**
3967 * xmlXPathCompareNodeSetString:
3968 * @ctxt: the XPath Parser context
3969 * @inf: less than (1) or greater than (0)
3970 * @strict: is the comparison strict
3971 * @arg: the node set
3972 * @s: the value
3973 *
3974 * Implement the compare operation between a nodeset and a string
3975 * @ns < @val (1, 1, ...
3976 * @ns <= @val (1, 0, ...
3977 * @ns > @val (0, 1, ...
3978 * @ns >= @val (0, 0, ...
3979 *
3980 * If one object to be compared is a node-set and the other is a string,
3981 * then the comparison will be true if and only if there is a node in
3982 * the node-set such that the result of performing the comparison on the
3983 * string-value of the node and the other string is true.
3984 *
3985 * Returns 0 or 1 depending on the results of the test.
3986 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003987static int
Owen Taylor3473f882001-02-23 17:55:21 +00003988xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
3989 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
3990 int i, ret = 0;
3991 xmlNodeSetPtr ns;
3992 xmlChar *str2;
3993
3994 if ((s == NULL) || (arg == NULL) ||
3995 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3996 xmlXPathFreeObject(arg);
3997 xmlXPathFreeObject(s);
3998 return(0);
3999 }
4000 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004001 if (ns != NULL) {
4002 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004003 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004004 if (str2 != NULL) {
4005 valuePush(ctxt,
4006 xmlXPathNewString(str2));
4007 xmlFree(str2);
4008 valuePush(ctxt, xmlXPathObjectCopy(s));
4009 ret = xmlXPathCompareValues(ctxt, inf, strict);
4010 if (ret)
4011 break;
4012 }
4013 }
Owen Taylor3473f882001-02-23 17:55:21 +00004014 }
4015 xmlXPathFreeObject(arg);
4016 xmlXPathFreeObject(s);
4017 return(ret);
4018}
4019
4020/**
4021 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004022 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00004023 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004024 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00004025 * @arg2: the second node set object
4026 *
4027 * Implement the compare operation on nodesets:
4028 *
4029 * If both objects to be compared are node-sets, then the comparison
4030 * will be true if and only if there is a node in the first node-set
4031 * and a node in the second node-set such that the result of performing
4032 * the comparison on the string-values of the two nodes is true.
4033 * ....
4034 * When neither object to be compared is a node-set and the operator
4035 * is <=, <, >= or >, then the objects are compared by converting both
4036 * objects to numbers and comparing the numbers according to IEEE 754.
4037 * ....
4038 * The number function converts its argument to a number as follows:
4039 * - a string that consists of optional whitespace followed by an
4040 * optional minus sign followed by a Number followed by whitespace
4041 * is converted to the IEEE 754 number that is nearest (according
4042 * to the IEEE 754 round-to-nearest rule) to the mathematical value
4043 * represented by the string; any other string is converted to NaN
4044 *
4045 * Conclusion all nodes need to be converted first to their string value
4046 * and then the comparison must be done when possible
4047 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004048static int
4049xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00004050 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4051 int i, j, init = 0;
4052 double val1;
4053 double *values2;
4054 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004055 xmlNodeSetPtr ns1;
4056 xmlNodeSetPtr ns2;
4057
4058 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004059 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4060 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004061 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004062 }
Owen Taylor3473f882001-02-23 17:55:21 +00004063 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004064 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4065 xmlXPathFreeObject(arg1);
4066 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004067 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004068 }
Owen Taylor3473f882001-02-23 17:55:21 +00004069
4070 ns1 = arg1->nodesetval;
4071 ns2 = arg2->nodesetval;
4072
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004073 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004074 xmlXPathFreeObject(arg1);
4075 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004076 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004077 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004078 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004079 xmlXPathFreeObject(arg1);
4080 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004081 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004082 }
Owen Taylor3473f882001-02-23 17:55:21 +00004083
4084 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4085 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004086 xmlXPathFreeObject(arg1);
4087 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004088 return(0);
4089 }
4090 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004091 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004092 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004093 continue;
4094 for (j = 0;j < ns2->nodeNr;j++) {
4095 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004096 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004097 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004098 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004099 continue;
4100 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 else if (!inf && !strict)
4107 ret = (val1 >= values2[j]);
4108 if (ret)
4109 break;
4110 }
4111 if (ret)
4112 break;
4113 init = 1;
4114 }
4115 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004116 xmlXPathFreeObject(arg1);
4117 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004118 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004119}
4120
4121/**
4122 * xmlXPathCompareNodeSetValue:
4123 * @ctxt: the XPath Parser context
4124 * @inf: less than (1) or greater than (0)
4125 * @strict: is the comparison strict
4126 * @arg: the node set
4127 * @val: the value
4128 *
4129 * Implement the compare operation between a nodeset and a value
4130 * @ns < @val (1, 1, ...
4131 * @ns <= @val (1, 0, ...
4132 * @ns > @val (0, 1, ...
4133 * @ns >= @val (0, 0, ...
4134 *
4135 * If one object to be compared is a node-set and the other is a boolean,
4136 * then the comparison will be true if and only if the result of performing
4137 * the comparison on the boolean and on the result of converting
4138 * the node-set to a boolean using the boolean function is true.
4139 *
4140 * Returns 0 or 1 depending on the results of the test.
4141 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004142static int
Owen Taylor3473f882001-02-23 17:55:21 +00004143xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4144 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4145 if ((val == NULL) || (arg == NULL) ||
4146 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4147 return(0);
4148
4149 switch(val->type) {
4150 case XPATH_NUMBER:
4151 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4152 case XPATH_NODESET:
4153 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004154 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004155 case XPATH_STRING:
4156 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4157 case XPATH_BOOLEAN:
4158 valuePush(ctxt, arg);
4159 xmlXPathBooleanFunction(ctxt, 1);
4160 valuePush(ctxt, val);
4161 return(xmlXPathCompareValues(ctxt, inf, strict));
4162 default:
4163 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004164 }
4165 return(0);
4166}
4167
4168/**
4169 * xmlXPathEqualNodeSetString
4170 * @arg: the nodeset object argument
4171 * @str: the string to compare to.
4172 *
4173 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4174 * If one object to be compared is a node-set and the other is a string,
4175 * then the comparison will be true if and only if there is a node in
4176 * the node-set such that the result of performing the comparison on the
4177 * string-value of the node and the other string is true.
4178 *
4179 * Returns 0 or 1 depending on the results of the test.
4180 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004181static int
Daniel Veillardf06307e2001-07-03 10:35:50 +00004182xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str)
4183{
Owen Taylor3473f882001-02-23 17:55:21 +00004184 int i;
4185 xmlNodeSetPtr ns;
4186 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004187 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004188
4189 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004190 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4191 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004192 ns = arg->nodesetval;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004193 hash = xmlXPathStringHash(str);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004194 if (ns == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004195 return (0);
Daniel Veillard73c9c042001-07-05 20:02:54 +00004196 if (ns->nodeNr <= 0) {
4197 if (hash == 0)
4198 return(1);
4199 return(0);
4200 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004201 for (i = 0; i < ns->nodeNr; i++) {
4202 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4203 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4204 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4205 xmlFree(str2);
4206 return (1);
4207 }
4208 if (str2 != NULL)
4209 xmlFree(str2);
4210 }
Owen Taylor3473f882001-02-23 17:55:21 +00004211 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004212 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004213}
4214
4215/**
4216 * xmlXPathEqualNodeSetFloat
4217 * @arg: the nodeset object argument
4218 * @f: the float to compare to
4219 *
4220 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4221 * If one object to be compared is a node-set and the other is a number,
4222 * then the comparison will be true if and only if there is a node in
4223 * the node-set such that the result of performing the comparison on the
4224 * number to be compared and on the result of converting the string-value
4225 * of that node to a number using the number function is true.
4226 *
4227 * Returns 0 or 1 depending on the results of the test.
4228 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004229static int
Owen Taylor3473f882001-02-23 17:55:21 +00004230xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, double f) {
4231 char buf[100] = "";
4232
4233 if ((arg == NULL) ||
4234 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4235 return(0);
4236
Bjorn Reesee1dc0112001-03-03 12:09:03 +00004237 xmlXPathFormatNumber(f, buf, sizeof(buf));
Owen Taylor3473f882001-02-23 17:55:21 +00004238 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
4239}
4240
4241
4242/**
4243 * xmlXPathEqualNodeSets
4244 * @arg1: first nodeset object argument
4245 * @arg2: second nodeset object argument
4246 *
4247 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
4248 * If both objects to be compared are node-sets, then the comparison
4249 * will be true if and only if there is a node in the first node-set and
4250 * a node in the second node-set such that the result of performing the
4251 * comparison on the string-values of the two nodes is true.
4252 *
4253 * (needless to say, this is a costly operation)
4254 *
4255 * Returns 0 or 1 depending on the results of the test.
4256 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004257static int
Owen Taylor3473f882001-02-23 17:55:21 +00004258xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4259 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004260 unsigned int *hashs1;
4261 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004262 xmlChar **values1;
4263 xmlChar **values2;
4264 int ret = 0;
4265 xmlNodeSetPtr ns1;
4266 xmlNodeSetPtr ns2;
4267
4268 if ((arg1 == NULL) ||
4269 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4270 return(0);
4271 if ((arg2 == NULL) ||
4272 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4273 return(0);
4274
4275 ns1 = arg1->nodesetval;
4276 ns2 = arg2->nodesetval;
4277
Daniel Veillard911f49a2001-04-07 15:39:35 +00004278 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004279 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004280 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004281 return(0);
4282
4283 /*
4284 * check if there is a node pertaining to both sets
4285 */
4286 for (i = 0;i < ns1->nodeNr;i++)
4287 for (j = 0;j < ns2->nodeNr;j++)
4288 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4289 return(1);
4290
4291 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
4292 if (values1 == NULL)
4293 return(0);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004294 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4295 if (hashs1 == NULL) {
4296 xmlFree(values1);
4297 return(0);
4298 }
Owen Taylor3473f882001-02-23 17:55:21 +00004299 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4300 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4301 if (values2 == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004302 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004303 xmlFree(values1);
4304 return(0);
4305 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004306 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4307 if (hashs2 == NULL) {
4308 xmlFree(hashs1);
4309 xmlFree(values1);
4310 xmlFree(values2);
4311 return(0);
4312 }
Owen Taylor3473f882001-02-23 17:55:21 +00004313 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4314 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004315 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004316 for (j = 0;j < ns2->nodeNr;j++) {
4317 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004318 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
4319 if (hashs1[i] == hashs2[j]) {
4320 if (values1[i] == NULL)
4321 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4322 if (values2[j] == NULL)
4323 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
4324 ret = xmlStrEqual(values1[i], values2[j]);
4325 if (ret)
4326 break;
4327 }
Owen Taylor3473f882001-02-23 17:55:21 +00004328 }
4329 if (ret)
4330 break;
4331 }
4332 for (i = 0;i < ns1->nodeNr;i++)
4333 if (values1[i] != NULL)
4334 xmlFree(values1[i]);
4335 for (j = 0;j < ns2->nodeNr;j++)
4336 if (values2[j] != NULL)
4337 xmlFree(values2[j]);
4338 xmlFree(values1);
4339 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004340 xmlFree(hashs1);
4341 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004342 return(ret);
4343}
4344
4345/**
4346 * xmlXPathEqualValues:
4347 * @ctxt: the XPath Parser context
4348 *
4349 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4350 *
4351 * Returns 0 or 1 depending on the results of the test.
4352 */
4353int
4354xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4355 xmlXPathObjectPtr arg1, arg2;
4356 int ret = 0;
4357
4358 arg1 = valuePop(ctxt);
4359 if (arg1 == NULL)
4360 XP_ERROR0(XPATH_INVALID_OPERAND);
4361
4362 arg2 = valuePop(ctxt);
4363 if (arg2 == NULL) {
4364 xmlXPathFreeObject(arg1);
4365 XP_ERROR0(XPATH_INVALID_OPERAND);
4366 }
4367
4368 if (arg1 == arg2) {
4369#ifdef DEBUG_EXPR
4370 xmlGenericError(xmlGenericErrorContext,
4371 "Equal: by pointer\n");
4372#endif
4373 return(1);
4374 }
4375
4376 switch (arg1->type) {
4377 case XPATH_UNDEFINED:
4378#ifdef DEBUG_EXPR
4379 xmlGenericError(xmlGenericErrorContext,
4380 "Equal: undefined\n");
4381#endif
4382 break;
4383 case XPATH_XSLT_TREE:
4384 case XPATH_NODESET:
4385 switch (arg2->type) {
4386 case XPATH_UNDEFINED:
4387#ifdef DEBUG_EXPR
4388 xmlGenericError(xmlGenericErrorContext,
4389 "Equal: undefined\n");
4390#endif
4391 break;
4392 case XPATH_XSLT_TREE:
4393 case XPATH_NODESET:
4394 ret = xmlXPathEqualNodeSets(arg1, arg2);
4395 break;
4396 case XPATH_BOOLEAN:
4397 if ((arg1->nodesetval == NULL) ||
4398 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4399 else
4400 ret = 1;
4401 ret = (ret == arg2->boolval);
4402 break;
4403 case XPATH_NUMBER:
4404 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
4405 break;
4406 case XPATH_STRING:
4407 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
4408 break;
4409 case XPATH_USERS:
4410 case XPATH_POINT:
4411 case XPATH_RANGE:
4412 case XPATH_LOCATIONSET:
4413 TODO
4414 break;
4415 }
4416 break;
4417 case XPATH_BOOLEAN:
4418 switch (arg2->type) {
4419 case XPATH_UNDEFINED:
4420#ifdef DEBUG_EXPR
4421 xmlGenericError(xmlGenericErrorContext,
4422 "Equal: undefined\n");
4423#endif
4424 break;
4425 case XPATH_NODESET:
4426 case XPATH_XSLT_TREE:
4427 if ((arg2->nodesetval == NULL) ||
Daniel Veillardbd6e6312002-04-01 08:04:14 +00004428 (arg2->nodesetval->nodeNr == 0))
4429 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004430 else
4431 ret = 1;
Daniel Veillardbd6e6312002-04-01 08:04:14 +00004432 ret = (ret == arg1->boolval);
Owen Taylor3473f882001-02-23 17:55:21 +00004433 break;
4434 case XPATH_BOOLEAN:
4435#ifdef DEBUG_EXPR
4436 xmlGenericError(xmlGenericErrorContext,
4437 "Equal: %d boolean %d \n",
4438 arg1->boolval, arg2->boolval);
4439#endif
4440 ret = (arg1->boolval == arg2->boolval);
4441 break;
4442 case XPATH_NUMBER:
4443 if (arg2->floatval) ret = 1;
4444 else ret = 0;
4445 ret = (arg1->boolval == ret);
4446 break;
4447 case XPATH_STRING:
4448 if ((arg2->stringval == NULL) ||
4449 (arg2->stringval[0] == 0)) ret = 0;
4450 else
4451 ret = 1;
4452 ret = (arg1->boolval == ret);
4453 break;
4454 case XPATH_USERS:
4455 case XPATH_POINT:
4456 case XPATH_RANGE:
4457 case XPATH_LOCATIONSET:
4458 TODO
4459 break;
4460 }
4461 break;
4462 case XPATH_NUMBER:
4463 switch (arg2->type) {
4464 case XPATH_UNDEFINED:
4465#ifdef DEBUG_EXPR
4466 xmlGenericError(xmlGenericErrorContext,
4467 "Equal: undefined\n");
4468#endif
4469 break;
4470 case XPATH_NODESET:
4471 case XPATH_XSLT_TREE:
4472 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
4473 break;
4474 case XPATH_BOOLEAN:
4475 if (arg1->floatval) ret = 1;
4476 else ret = 0;
4477 ret = (arg2->boolval == ret);
4478 break;
4479 case XPATH_STRING:
4480 valuePush(ctxt, arg2);
4481 xmlXPathNumberFunction(ctxt, 1);
4482 arg2 = valuePop(ctxt);
4483 /* no break on purpose */
4484 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004485 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004486 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4487 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004488 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4489 if (xmlXPathIsInf(arg2->floatval) == 1)
4490 ret = 1;
4491 else
4492 ret = 0;
4493 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4494 if (xmlXPathIsInf(arg2->floatval) == -1)
4495 ret = 1;
4496 else
4497 ret = 0;
4498 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4499 if (xmlXPathIsInf(arg1->floatval) == 1)
4500 ret = 1;
4501 else
4502 ret = 0;
4503 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4504 if (xmlXPathIsInf(arg1->floatval) == -1)
4505 ret = 1;
4506 else
4507 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004508 } else {
4509 ret = (arg1->floatval == arg2->floatval);
4510 }
Owen Taylor3473f882001-02-23 17:55:21 +00004511 break;
4512 case XPATH_USERS:
4513 case XPATH_POINT:
4514 case XPATH_RANGE:
4515 case XPATH_LOCATIONSET:
4516 TODO
4517 break;
4518 }
4519 break;
4520 case XPATH_STRING:
4521 switch (arg2->type) {
4522 case XPATH_UNDEFINED:
4523#ifdef DEBUG_EXPR
4524 xmlGenericError(xmlGenericErrorContext,
4525 "Equal: undefined\n");
4526#endif
4527 break;
4528 case XPATH_NODESET:
4529 case XPATH_XSLT_TREE:
4530 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
4531 break;
4532 case XPATH_BOOLEAN:
4533 if ((arg1->stringval == NULL) ||
4534 (arg1->stringval[0] == 0)) ret = 0;
4535 else
4536 ret = 1;
4537 ret = (arg2->boolval == ret);
4538 break;
4539 case XPATH_STRING:
4540 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4541 break;
4542 case XPATH_NUMBER:
4543 valuePush(ctxt, arg1);
4544 xmlXPathNumberFunction(ctxt, 1);
4545 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004546 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004547 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4548 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004549 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4550 if (xmlXPathIsInf(arg2->floatval) == 1)
4551 ret = 1;
4552 else
4553 ret = 0;
4554 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4555 if (xmlXPathIsInf(arg2->floatval) == -1)
4556 ret = 1;
4557 else
4558 ret = 0;
4559 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4560 if (xmlXPathIsInf(arg1->floatval) == 1)
4561 ret = 1;
4562 else
4563 ret = 0;
4564 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4565 if (xmlXPathIsInf(arg1->floatval) == -1)
4566 ret = 1;
4567 else
4568 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004569 } else {
4570 ret = (arg1->floatval == arg2->floatval);
4571 }
Owen Taylor3473f882001-02-23 17:55:21 +00004572 break;
4573 case XPATH_USERS:
4574 case XPATH_POINT:
4575 case XPATH_RANGE:
4576 case XPATH_LOCATIONSET:
4577 TODO
4578 break;
4579 }
4580 break;
4581 case XPATH_USERS:
4582 case XPATH_POINT:
4583 case XPATH_RANGE:
4584 case XPATH_LOCATIONSET:
4585 TODO
4586 break;
4587 }
4588 xmlXPathFreeObject(arg1);
4589 xmlXPathFreeObject(arg2);
4590 return(ret);
4591}
4592
4593
4594/**
4595 * xmlXPathCompareValues:
4596 * @ctxt: the XPath Parser context
4597 * @inf: less than (1) or greater than (0)
4598 * @strict: is the comparison strict
4599 *
4600 * Implement the compare operation on XPath objects:
4601 * @arg1 < @arg2 (1, 1, ...
4602 * @arg1 <= @arg2 (1, 0, ...
4603 * @arg1 > @arg2 (0, 1, ...
4604 * @arg1 >= @arg2 (0, 0, ...
4605 *
4606 * When neither object to be compared is a node-set and the operator is
4607 * <=, <, >=, >, then the objects are compared by converted both objects
4608 * to numbers and comparing the numbers according to IEEE 754. The <
4609 * comparison will be true if and only if the first number is less than the
4610 * second number. The <= comparison will be true if and only if the first
4611 * number is less than or equal to the second number. The > comparison
4612 * will be true if and only if the first number is greater than the second
4613 * number. The >= comparison will be true if and only if the first number
4614 * is greater than or equal to the second number.
4615 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004616 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00004617 */
4618int
4619xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004620 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004621 xmlXPathObjectPtr arg1, arg2;
4622
4623 arg2 = valuePop(ctxt);
4624 if (arg2 == NULL) {
4625 XP_ERROR0(XPATH_INVALID_OPERAND);
4626 }
4627
4628 arg1 = valuePop(ctxt);
4629 if (arg1 == NULL) {
4630 xmlXPathFreeObject(arg2);
4631 XP_ERROR0(XPATH_INVALID_OPERAND);
4632 }
4633
4634 if ((arg2->type == XPATH_NODESET) || (arg1->type == XPATH_NODESET)) {
4635 if ((arg2->type == XPATH_NODESET) && (arg1->type == XPATH_NODESET)) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004636 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004637 } else {
4638 if (arg1->type == XPATH_NODESET) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004639 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
4640 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004641 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004642 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
4643 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00004644 }
4645 }
4646 return(ret);
4647 }
4648
4649 if (arg1->type != XPATH_NUMBER) {
4650 valuePush(ctxt, arg1);
4651 xmlXPathNumberFunction(ctxt, 1);
4652 arg1 = valuePop(ctxt);
4653 }
4654 if (arg1->type != XPATH_NUMBER) {
4655 xmlXPathFreeObject(arg1);
4656 xmlXPathFreeObject(arg2);
4657 XP_ERROR0(XPATH_INVALID_OPERAND);
4658 }
4659 if (arg2->type != XPATH_NUMBER) {
4660 valuePush(ctxt, arg2);
4661 xmlXPathNumberFunction(ctxt, 1);
4662 arg2 = valuePop(ctxt);
4663 }
4664 if (arg2->type != XPATH_NUMBER) {
4665 xmlXPathFreeObject(arg1);
4666 xmlXPathFreeObject(arg2);
4667 XP_ERROR0(XPATH_INVALID_OPERAND);
4668 }
4669 /*
4670 * Add tests for infinity and nan
4671 * => feedback on 3.4 for Inf and NaN
4672 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004673 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00004674 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004675 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004676 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004677 arg1i=xmlXPathIsInf(arg1->floatval);
4678 arg2i=xmlXPathIsInf(arg2->floatval);
4679 if (inf && strict) {
4680 if ((arg1i == -1 && arg2i != -1) ||
4681 (arg2i == 1 && arg1i != 1)) {
4682 ret = 1;
4683 } else if (arg1i == 0 && arg2i == 0) {
4684 ret = (arg1->floatval < arg2->floatval);
4685 } else {
4686 ret = 0;
4687 }
4688 }
4689 else if (inf && !strict) {
4690 if (arg1i == -1 || arg2i == 1) {
4691 ret = 1;
4692 } else if (arg1i == 0 && arg2i == 0) {
4693 ret = (arg1->floatval <= arg2->floatval);
4694 } else {
4695 ret = 0;
4696 }
4697 }
4698 else if (!inf && strict) {
4699 if ((arg1i == 1 && arg2i != 1) ||
4700 (arg2i == -1 && arg1i != -1)) {
4701 ret = 1;
4702 } else if (arg1i == 0 && arg2i == 0) {
4703 ret = (arg1->floatval > arg2->floatval);
4704 } else {
4705 ret = 0;
4706 }
4707 }
4708 else if (!inf && !strict) {
4709 if (arg1i == 1 || arg2i == -1) {
4710 ret = 1;
4711 } else if (arg1i == 0 && arg2i == 0) {
4712 ret = (arg1->floatval >= arg2->floatval);
4713 } else {
4714 ret = 0;
4715 }
4716 }
Daniel Veillard21458c82002-03-27 16:12:22 +00004717 }
Owen Taylor3473f882001-02-23 17:55:21 +00004718 xmlXPathFreeObject(arg1);
4719 xmlXPathFreeObject(arg2);
4720 return(ret);
4721}
4722
4723/**
4724 * xmlXPathValueFlipSign:
4725 * @ctxt: the XPath Parser context
4726 *
4727 * Implement the unary - operation on an XPath object
4728 * The numeric operators convert their operands to numbers as if
4729 * by calling the number function.
4730 */
4731void
4732xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004733 CAST_TO_NUMBER;
4734 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00004735 if (xmlXPathIsNaN(ctxt->value->floatval))
4736 ctxt->value->floatval=xmlXPathNAN;
4737 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
4738 ctxt->value->floatval=xmlXPathNINF;
4739 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
4740 ctxt->value->floatval=xmlXPathPINF;
4741 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00004742 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
4743 ctxt->value->floatval = xmlXPathNZERO;
4744 else
4745 ctxt->value->floatval = 0;
4746 }
4747 else
4748 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00004749}
4750
4751/**
4752 * xmlXPathAddValues:
4753 * @ctxt: the XPath Parser context
4754 *
4755 * Implement the add operation on XPath objects:
4756 * The numeric operators convert their operands to numbers as if
4757 * by calling the number function.
4758 */
4759void
4760xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
4761 xmlXPathObjectPtr arg;
4762 double val;
4763
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004764 arg = valuePop(ctxt);
4765 if (arg == NULL)
4766 XP_ERROR(XPATH_INVALID_OPERAND);
4767 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004768 xmlXPathFreeObject(arg);
4769
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004770 CAST_TO_NUMBER;
4771 CHECK_TYPE(XPATH_NUMBER);
4772 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00004773}
4774
4775/**
4776 * xmlXPathSubValues:
4777 * @ctxt: the XPath Parser context
4778 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004779 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00004780 * The numeric operators convert their operands to numbers as if
4781 * by calling the number function.
4782 */
4783void
4784xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
4785 xmlXPathObjectPtr arg;
4786 double val;
4787
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004788 arg = valuePop(ctxt);
4789 if (arg == NULL)
4790 XP_ERROR(XPATH_INVALID_OPERAND);
4791 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004792 xmlXPathFreeObject(arg);
4793
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004794 CAST_TO_NUMBER;
4795 CHECK_TYPE(XPATH_NUMBER);
4796 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004797}
4798
4799/**
4800 * xmlXPathMultValues:
4801 * @ctxt: the XPath Parser context
4802 *
4803 * Implement the multiply operation on XPath objects:
4804 * The numeric operators convert their operands to numbers as if
4805 * by calling the number function.
4806 */
4807void
4808xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
4809 xmlXPathObjectPtr arg;
4810 double val;
4811
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004812 arg = valuePop(ctxt);
4813 if (arg == NULL)
4814 XP_ERROR(XPATH_INVALID_OPERAND);
4815 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004816 xmlXPathFreeObject(arg);
4817
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004818 CAST_TO_NUMBER;
4819 CHECK_TYPE(XPATH_NUMBER);
4820 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004821}
4822
4823/**
4824 * xmlXPathDivValues:
4825 * @ctxt: the XPath Parser context
4826 *
4827 * Implement the div operation on XPath objects @arg1 / @arg2:
4828 * The numeric operators convert their operands to numbers as if
4829 * by calling the number function.
4830 */
4831void
4832xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
4833 xmlXPathObjectPtr arg;
4834 double val;
4835
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004836 arg = valuePop(ctxt);
4837 if (arg == NULL)
4838 XP_ERROR(XPATH_INVALID_OPERAND);
4839 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004840 xmlXPathFreeObject(arg);
4841
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004842 CAST_TO_NUMBER;
4843 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00004844 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
4845 ctxt->value->floatval = xmlXPathNAN;
4846 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00004847 if (ctxt->value->floatval == 0)
4848 ctxt->value->floatval = xmlXPathNAN;
4849 else if (ctxt->value->floatval > 0)
4850 ctxt->value->floatval = xmlXPathNINF;
4851 else if (ctxt->value->floatval < 0)
4852 ctxt->value->floatval = xmlXPathPINF;
4853 }
4854 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00004855 if (ctxt->value->floatval == 0)
4856 ctxt->value->floatval = xmlXPathNAN;
4857 else if (ctxt->value->floatval > 0)
4858 ctxt->value->floatval = xmlXPathPINF;
4859 else if (ctxt->value->floatval < 0)
4860 ctxt->value->floatval = xmlXPathNINF;
4861 } else
4862 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004863}
4864
4865/**
4866 * xmlXPathModValues:
4867 * @ctxt: the XPath Parser context
4868 *
4869 * Implement the mod operation on XPath objects: @arg1 / @arg2
4870 * The numeric operators convert their operands to numbers as if
4871 * by calling the number function.
4872 */
4873void
4874xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
4875 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00004876 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00004877
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004878 arg = valuePop(ctxt);
4879 if (arg == NULL)
4880 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00004881 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004882 xmlXPathFreeObject(arg);
4883
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004884 CAST_TO_NUMBER;
4885 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00004886 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00004887 if (arg2 == 0)
4888 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00004889 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00004890 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00004891 }
Owen Taylor3473f882001-02-23 17:55:21 +00004892}
4893
4894/************************************************************************
4895 * *
4896 * The traversal functions *
4897 * *
4898 ************************************************************************/
4899
Owen Taylor3473f882001-02-23 17:55:21 +00004900/*
4901 * A traversal function enumerates nodes along an axis.
4902 * Initially it must be called with NULL, and it indicates
4903 * termination on the axis by returning NULL.
4904 */
4905typedef xmlNodePtr (*xmlXPathTraversalFunction)
4906 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
4907
4908/**
4909 * xmlXPathNextSelf:
4910 * @ctxt: the XPath Parser context
4911 * @cur: the current node in the traversal
4912 *
4913 * Traversal function for the "self" direction
4914 * The self axis contains just the context node itself
4915 *
4916 * Returns the next element following that axis
4917 */
4918xmlNodePtr
4919xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4920 if (cur == NULL)
4921 return(ctxt->context->node);
4922 return(NULL);
4923}
4924
4925/**
4926 * xmlXPathNextChild:
4927 * @ctxt: the XPath Parser context
4928 * @cur: the current node in the traversal
4929 *
4930 * Traversal function for the "child" direction
4931 * The child axis contains the children of the context node in document order.
4932 *
4933 * Returns the next element following that axis
4934 */
4935xmlNodePtr
4936xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4937 if (cur == NULL) {
4938 if (ctxt->context->node == NULL) return(NULL);
4939 switch (ctxt->context->node->type) {
4940 case XML_ELEMENT_NODE:
4941 case XML_TEXT_NODE:
4942 case XML_CDATA_SECTION_NODE:
4943 case XML_ENTITY_REF_NODE:
4944 case XML_ENTITY_NODE:
4945 case XML_PI_NODE:
4946 case XML_COMMENT_NODE:
4947 case XML_NOTATION_NODE:
4948 case XML_DTD_NODE:
4949 return(ctxt->context->node->children);
4950 case XML_DOCUMENT_NODE:
4951 case XML_DOCUMENT_TYPE_NODE:
4952 case XML_DOCUMENT_FRAG_NODE:
4953 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004954#ifdef LIBXML_DOCB_ENABLED
4955 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004956#endif
4957 return(((xmlDocPtr) ctxt->context->node)->children);
4958 case XML_ELEMENT_DECL:
4959 case XML_ATTRIBUTE_DECL:
4960 case XML_ENTITY_DECL:
4961 case XML_ATTRIBUTE_NODE:
4962 case XML_NAMESPACE_DECL:
4963 case XML_XINCLUDE_START:
4964 case XML_XINCLUDE_END:
4965 return(NULL);
4966 }
4967 return(NULL);
4968 }
4969 if ((cur->type == XML_DOCUMENT_NODE) ||
4970 (cur->type == XML_HTML_DOCUMENT_NODE))
4971 return(NULL);
4972 return(cur->next);
4973}
4974
4975/**
4976 * xmlXPathNextDescendant:
4977 * @ctxt: the XPath Parser context
4978 * @cur: the current node in the traversal
4979 *
4980 * Traversal function for the "descendant" direction
4981 * the descendant axis contains the descendants of the context node in document
4982 * order; a descendant is a child or a child of a child and so on.
4983 *
4984 * Returns the next element following that axis
4985 */
4986xmlNodePtr
4987xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4988 if (cur == NULL) {
4989 if (ctxt->context->node == NULL)
4990 return(NULL);
4991 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4992 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4993 return(NULL);
4994
4995 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
4996 return(ctxt->context->doc->children);
4997 return(ctxt->context->node->children);
4998 }
4999
Daniel Veillard567e1b42001-08-01 15:53:47 +00005000 if (cur->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005001 if (cur->children->type != XML_ENTITY_DECL)
Daniel Veillard567e1b42001-08-01 15:53:47 +00005002 return(cur->children);
5003 }
5004
5005 if (cur == ctxt->context->node) return(NULL);
5006
Owen Taylor3473f882001-02-23 17:55:21 +00005007 if (cur->next != NULL) return(cur->next);
5008
5009 do {
5010 cur = cur->parent;
5011 if (cur == NULL) return(NULL);
5012 if (cur == ctxt->context->node) return(NULL);
5013 if (cur->next != NULL) {
5014 cur = cur->next;
5015 return(cur);
5016 }
5017 } while (cur != NULL);
5018 return(cur);
5019}
5020
5021/**
5022 * xmlXPathNextDescendantOrSelf:
5023 * @ctxt: the XPath Parser context
5024 * @cur: the current node in the traversal
5025 *
5026 * Traversal function for the "descendant-or-self" direction
5027 * the descendant-or-self axis contains the context node and the descendants
5028 * of the context node in document order; thus the context node is the first
5029 * node on the axis, and the first child of the context node is the second node
5030 * on the axis
5031 *
5032 * Returns the next element following that axis
5033 */
5034xmlNodePtr
5035xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5036 if (cur == NULL) {
5037 if (ctxt->context->node == NULL)
5038 return(NULL);
5039 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5040 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5041 return(NULL);
5042 return(ctxt->context->node);
5043 }
5044
5045 return(xmlXPathNextDescendant(ctxt, cur));
5046}
5047
5048/**
5049 * xmlXPathNextParent:
5050 * @ctxt: the XPath Parser context
5051 * @cur: the current node in the traversal
5052 *
5053 * Traversal function for the "parent" direction
5054 * The parent axis contains the parent of the context node, if there is one.
5055 *
5056 * Returns the next element following that axis
5057 */
5058xmlNodePtr
5059xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5060 /*
5061 * the parent of an attribute or namespace node is the element
5062 * to which the attribute or namespace node is attached
5063 * Namespace handling !!!
5064 */
5065 if (cur == NULL) {
5066 if (ctxt->context->node == NULL) return(NULL);
5067 switch (ctxt->context->node->type) {
5068 case XML_ELEMENT_NODE:
5069 case XML_TEXT_NODE:
5070 case XML_CDATA_SECTION_NODE:
5071 case XML_ENTITY_REF_NODE:
5072 case XML_ENTITY_NODE:
5073 case XML_PI_NODE:
5074 case XML_COMMENT_NODE:
5075 case XML_NOTATION_NODE:
5076 case XML_DTD_NODE:
5077 case XML_ELEMENT_DECL:
5078 case XML_ATTRIBUTE_DECL:
5079 case XML_XINCLUDE_START:
5080 case XML_XINCLUDE_END:
5081 case XML_ENTITY_DECL:
5082 if (ctxt->context->node->parent == NULL)
5083 return((xmlNodePtr) ctxt->context->doc);
5084 return(ctxt->context->node->parent);
5085 case XML_ATTRIBUTE_NODE: {
5086 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5087
5088 return(att->parent);
5089 }
5090 case XML_DOCUMENT_NODE:
5091 case XML_DOCUMENT_TYPE_NODE:
5092 case XML_DOCUMENT_FRAG_NODE:
5093 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005094#ifdef LIBXML_DOCB_ENABLED
5095 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005096#endif
5097 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005098 case XML_NAMESPACE_DECL: {
5099 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5100
5101 if ((ns->next != NULL) &&
5102 (ns->next->type != XML_NAMESPACE_DECL))
5103 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005104 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005105 }
Owen Taylor3473f882001-02-23 17:55:21 +00005106 }
5107 }
5108 return(NULL);
5109}
5110
5111/**
5112 * xmlXPathNextAncestor:
5113 * @ctxt: the XPath Parser context
5114 * @cur: the current node in the traversal
5115 *
5116 * Traversal function for the "ancestor" direction
5117 * the ancestor axis contains the ancestors of the context node; the ancestors
5118 * of the context node consist of the parent of context node and the parent's
5119 * parent and so on; the nodes are ordered in reverse document order; thus the
5120 * parent is the first node on the axis, and the parent's parent is the second
5121 * node on the axis
5122 *
5123 * Returns the next element following that axis
5124 */
5125xmlNodePtr
5126xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5127 /*
5128 * the parent of an attribute or namespace node is the element
5129 * to which the attribute or namespace node is attached
5130 * !!!!!!!!!!!!!
5131 */
5132 if (cur == NULL) {
5133 if (ctxt->context->node == NULL) return(NULL);
5134 switch (ctxt->context->node->type) {
5135 case XML_ELEMENT_NODE:
5136 case XML_TEXT_NODE:
5137 case XML_CDATA_SECTION_NODE:
5138 case XML_ENTITY_REF_NODE:
5139 case XML_ENTITY_NODE:
5140 case XML_PI_NODE:
5141 case XML_COMMENT_NODE:
5142 case XML_DTD_NODE:
5143 case XML_ELEMENT_DECL:
5144 case XML_ATTRIBUTE_DECL:
5145 case XML_ENTITY_DECL:
5146 case XML_NOTATION_NODE:
5147 case XML_XINCLUDE_START:
5148 case XML_XINCLUDE_END:
5149 if (ctxt->context->node->parent == NULL)
5150 return((xmlNodePtr) ctxt->context->doc);
5151 return(ctxt->context->node->parent);
5152 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005153 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005154
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005155 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005156 }
5157 case XML_DOCUMENT_NODE:
5158 case XML_DOCUMENT_TYPE_NODE:
5159 case XML_DOCUMENT_FRAG_NODE:
5160 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005161#ifdef LIBXML_DOCB_ENABLED
5162 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005163#endif
5164 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005165 case XML_NAMESPACE_DECL: {
5166 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5167
5168 if ((ns->next != NULL) &&
5169 (ns->next->type != XML_NAMESPACE_DECL))
5170 return((xmlNodePtr) ns->next);
5171 /* Bad, how did that namespace ended-up there ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005172 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005173 }
Owen Taylor3473f882001-02-23 17:55:21 +00005174 }
5175 return(NULL);
5176 }
5177 if (cur == ctxt->context->doc->children)
5178 return((xmlNodePtr) ctxt->context->doc);
5179 if (cur == (xmlNodePtr) ctxt->context->doc)
5180 return(NULL);
5181 switch (cur->type) {
5182 case XML_ELEMENT_NODE:
5183 case XML_TEXT_NODE:
5184 case XML_CDATA_SECTION_NODE:
5185 case XML_ENTITY_REF_NODE:
5186 case XML_ENTITY_NODE:
5187 case XML_PI_NODE:
5188 case XML_COMMENT_NODE:
5189 case XML_NOTATION_NODE:
5190 case XML_DTD_NODE:
5191 case XML_ELEMENT_DECL:
5192 case XML_ATTRIBUTE_DECL:
5193 case XML_ENTITY_DECL:
5194 case XML_XINCLUDE_START:
5195 case XML_XINCLUDE_END:
5196 return(cur->parent);
5197 case XML_ATTRIBUTE_NODE: {
5198 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5199
5200 return(att->parent);
5201 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005202 case XML_NAMESPACE_DECL: {
5203 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5204
5205 if ((ns->next != NULL) &&
5206 (ns->next->type != XML_NAMESPACE_DECL))
5207 return((xmlNodePtr) ns->next);
5208 /* Bad, how did that namespace ended-up there ? */
5209 return(NULL);
5210 }
Owen Taylor3473f882001-02-23 17:55:21 +00005211 case XML_DOCUMENT_NODE:
5212 case XML_DOCUMENT_TYPE_NODE:
5213 case XML_DOCUMENT_FRAG_NODE:
5214 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005215#ifdef LIBXML_DOCB_ENABLED
5216 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005217#endif
5218 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005219 }
5220 return(NULL);
5221}
5222
5223/**
5224 * xmlXPathNextAncestorOrSelf:
5225 * @ctxt: the XPath Parser context
5226 * @cur: the current node in the traversal
5227 *
5228 * Traversal function for the "ancestor-or-self" direction
5229 * he ancestor-or-self axis contains the context node and ancestors of
5230 * the context node in reverse document order; thus the context node is
5231 * the first node on the axis, and the context node's parent the second;
5232 * parent here is defined the same as with the parent axis.
5233 *
5234 * Returns the next element following that axis
5235 */
5236xmlNodePtr
5237xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5238 if (cur == NULL)
5239 return(ctxt->context->node);
5240 return(xmlXPathNextAncestor(ctxt, cur));
5241}
5242
5243/**
5244 * xmlXPathNextFollowingSibling:
5245 * @ctxt: the XPath Parser context
5246 * @cur: the current node in the traversal
5247 *
5248 * Traversal function for the "following-sibling" direction
5249 * The following-sibling axis contains the following siblings of the context
5250 * node in document order.
5251 *
5252 * Returns the next element following that axis
5253 */
5254xmlNodePtr
5255xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5256 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5257 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5258 return(NULL);
5259 if (cur == (xmlNodePtr) ctxt->context->doc)
5260 return(NULL);
5261 if (cur == NULL)
5262 return(ctxt->context->node->next);
5263 return(cur->next);
5264}
5265
5266/**
5267 * xmlXPathNextPrecedingSibling:
5268 * @ctxt: the XPath Parser context
5269 * @cur: the current node in the traversal
5270 *
5271 * Traversal function for the "preceding-sibling" direction
5272 * The preceding-sibling axis contains the preceding siblings of the context
5273 * node in reverse document order; the first preceding sibling is first on the
5274 * axis; the sibling preceding that node is the second on the axis and so on.
5275 *
5276 * Returns the next element following that axis
5277 */
5278xmlNodePtr
5279xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5280 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5281 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5282 return(NULL);
5283 if (cur == (xmlNodePtr) ctxt->context->doc)
5284 return(NULL);
5285 if (cur == NULL)
5286 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005287 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5288 cur = cur->prev;
5289 if (cur == NULL)
5290 return(ctxt->context->node->prev);
5291 }
Owen Taylor3473f882001-02-23 17:55:21 +00005292 return(cur->prev);
5293}
5294
5295/**
5296 * xmlXPathNextFollowing:
5297 * @ctxt: the XPath Parser context
5298 * @cur: the current node in the traversal
5299 *
5300 * Traversal function for the "following" direction
5301 * The following axis contains all nodes in the same document as the context
5302 * node that are after the context node in document order, excluding any
5303 * descendants and excluding attribute nodes and namespace nodes; the nodes
5304 * are ordered in document order
5305 *
5306 * Returns the next element following that axis
5307 */
5308xmlNodePtr
5309xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5310 if (cur != NULL && cur->children != NULL)
5311 return cur->children ;
5312 if (cur == NULL) cur = ctxt->context->node;
5313 if (cur == NULL) return(NULL) ; /* ERROR */
5314 if (cur->next != NULL) return(cur->next) ;
5315 do {
5316 cur = cur->parent;
5317 if (cur == NULL) return(NULL);
5318 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5319 if (cur->next != NULL) return(cur->next);
5320 } while (cur != NULL);
5321 return(cur);
5322}
5323
5324/*
5325 * xmlXPathIsAncestor:
5326 * @ancestor: the ancestor node
5327 * @node: the current node
5328 *
5329 * Check that @ancestor is a @node's ancestor
5330 *
5331 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5332 */
5333static int
5334xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5335 if ((ancestor == NULL) || (node == NULL)) return(0);
5336 /* nodes need to be in the same document */
5337 if (ancestor->doc != node->doc) return(0);
5338 /* avoid searching if ancestor or node is the root node */
5339 if (ancestor == (xmlNodePtr) node->doc) return(1);
5340 if (node == (xmlNodePtr) ancestor->doc) return(0);
5341 while (node->parent != NULL) {
5342 if (node->parent == ancestor)
5343 return(1);
5344 node = node->parent;
5345 }
5346 return(0);
5347}
5348
5349/**
5350 * xmlXPathNextPreceding:
5351 * @ctxt: the XPath Parser context
5352 * @cur: the current node in the traversal
5353 *
5354 * Traversal function for the "preceding" direction
5355 * the preceding axis contains all nodes in the same document as the context
5356 * node that are before the context node in document order, excluding any
5357 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5358 * ordered in reverse document order
5359 *
5360 * Returns the next element following that axis
5361 */
5362xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005363xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5364{
Owen Taylor3473f882001-02-23 17:55:21 +00005365 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005366 cur = ctxt->context->node;
5367 if (cur == NULL)
5368 return (NULL);
5369 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5370 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005371 do {
5372 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005373 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5374 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005375 }
5376
5377 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005378 if (cur == NULL)
5379 return (NULL);
5380 if (cur == ctxt->context->doc->children)
5381 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005382 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005383 return (cur);
5384}
5385
5386/**
5387 * xmlXPathNextPrecedingInternal:
5388 * @ctxt: the XPath Parser context
5389 * @cur: the current node in the traversal
5390 *
5391 * Traversal function for the "preceding" direction
5392 * the preceding axis contains all nodes in the same document as the context
5393 * node that are before the context node in document order, excluding any
5394 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5395 * ordered in reverse document order
5396 * This is a faster implementation but internal only since it requires a
5397 * state kept in the parser context: ctxt->ancestor.
5398 *
5399 * Returns the next element following that axis
5400 */
5401static xmlNodePtr
5402xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5403 xmlNodePtr cur)
5404{
5405 if (cur == NULL) {
5406 cur = ctxt->context->node;
5407 if (cur == NULL)
5408 return (NULL);
5409 ctxt->ancestor = cur->parent;
5410 }
5411 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5412 cur = cur->prev;
5413 while (cur->prev == NULL) {
5414 cur = cur->parent;
5415 if (cur == NULL)
5416 return (NULL);
5417 if (cur == ctxt->context->doc->children)
5418 return (NULL);
5419 if (cur != ctxt->ancestor)
5420 return (cur);
5421 ctxt->ancestor = cur->parent;
5422 }
5423 cur = cur->prev;
5424 while (cur->last != NULL)
5425 cur = cur->last;
5426 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005427}
5428
5429/**
5430 * xmlXPathNextNamespace:
5431 * @ctxt: the XPath Parser context
5432 * @cur: the current attribute in the traversal
5433 *
5434 * Traversal function for the "namespace" direction
5435 * the namespace axis contains the namespace nodes of the context node;
5436 * the order of nodes on this axis is implementation-defined; the axis will
5437 * be empty unless the context node is an element
5438 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005439 * We keep the XML namespace node at the end of the list.
5440 *
Owen Taylor3473f882001-02-23 17:55:21 +00005441 * Returns the next element following that axis
5442 */
5443xmlNodePtr
5444xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5445 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00005446 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005447 if (ctxt->context->tmpNsList != NULL)
5448 xmlFree(ctxt->context->tmpNsList);
5449 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005450 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005451 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005452 if (ctxt->context->tmpNsList != NULL) {
5453 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
5454 ctxt->context->tmpNsNr++;
5455 }
5456 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005457 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005458 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00005459 if (ctxt->context->tmpNsNr > 0) {
5460 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
5461 } else {
5462 if (ctxt->context->tmpNsList != NULL)
5463 xmlFree(ctxt->context->tmpNsList);
5464 ctxt->context->tmpNsList = NULL;
5465 return(NULL);
5466 }
Owen Taylor3473f882001-02-23 17:55:21 +00005467}
5468
5469/**
5470 * xmlXPathNextAttribute:
5471 * @ctxt: the XPath Parser context
5472 * @cur: the current attribute in the traversal
5473 *
5474 * Traversal function for the "attribute" direction
5475 * TODO: support DTD inherited default attributes
5476 *
5477 * Returns the next element following that axis
5478 */
5479xmlNodePtr
5480xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005481 if (ctxt->context->node == NULL)
5482 return(NULL);
5483 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5484 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005485 if (cur == NULL) {
5486 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5487 return(NULL);
5488 return((xmlNodePtr)ctxt->context->node->properties);
5489 }
5490 return((xmlNodePtr)cur->next);
5491}
5492
5493/************************************************************************
5494 * *
5495 * NodeTest Functions *
5496 * *
5497 ************************************************************************/
5498
Owen Taylor3473f882001-02-23 17:55:21 +00005499#define IS_FUNCTION 200
5500
Owen Taylor3473f882001-02-23 17:55:21 +00005501
5502/************************************************************************
5503 * *
5504 * Implicit tree core function library *
5505 * *
5506 ************************************************************************/
5507
5508/**
5509 * xmlXPathRoot:
5510 * @ctxt: the XPath Parser context
5511 *
5512 * Initialize the context to the root of the document
5513 */
5514void
5515xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5516 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5517 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5518}
5519
5520/************************************************************************
5521 * *
5522 * The explicit core function library *
5523 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5524 * *
5525 ************************************************************************/
5526
5527
5528/**
5529 * xmlXPathLastFunction:
5530 * @ctxt: the XPath Parser context
5531 * @nargs: the number of arguments
5532 *
5533 * Implement the last() XPath function
5534 * number last()
5535 * The last function returns the number of nodes in the context node list.
5536 */
5537void
5538xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5539 CHECK_ARITY(0);
5540 if (ctxt->context->contextSize >= 0) {
5541 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5542#ifdef DEBUG_EXPR
5543 xmlGenericError(xmlGenericErrorContext,
5544 "last() : %d\n", ctxt->context->contextSize);
5545#endif
5546 } else {
5547 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5548 }
5549}
5550
5551/**
5552 * xmlXPathPositionFunction:
5553 * @ctxt: the XPath Parser context
5554 * @nargs: the number of arguments
5555 *
5556 * Implement the position() XPath function
5557 * number position()
5558 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005559 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00005560 * will be equal to last().
5561 */
5562void
5563xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5564 CHECK_ARITY(0);
5565 if (ctxt->context->proximityPosition >= 0) {
5566 valuePush(ctxt,
5567 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5568#ifdef DEBUG_EXPR
5569 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5570 ctxt->context->proximityPosition);
5571#endif
5572 } else {
5573 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5574 }
5575}
5576
5577/**
5578 * xmlXPathCountFunction:
5579 * @ctxt: the XPath Parser context
5580 * @nargs: the number of arguments
5581 *
5582 * Implement the count() XPath function
5583 * number count(node-set)
5584 */
5585void
5586xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5587 xmlXPathObjectPtr cur;
5588
5589 CHECK_ARITY(1);
5590 if ((ctxt->value == NULL) ||
5591 ((ctxt->value->type != XPATH_NODESET) &&
5592 (ctxt->value->type != XPATH_XSLT_TREE)))
5593 XP_ERROR(XPATH_INVALID_TYPE);
5594 cur = valuePop(ctxt);
5595
Daniel Veillard911f49a2001-04-07 15:39:35 +00005596 if ((cur == NULL) || (cur->nodesetval == NULL))
5597 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00005598 else if (cur->type == XPATH_NODESET) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00005599 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00005600 } else {
5601 if ((cur->nodesetval->nodeNr != 1) ||
5602 (cur->nodesetval->nodeTab == NULL)) {
5603 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5604 } else {
5605 xmlNodePtr tmp;
5606 int i = 0;
5607
5608 tmp = cur->nodesetval->nodeTab[0];
5609 if (tmp != NULL) {
5610 tmp = tmp->children;
5611 while (tmp != NULL) {
5612 tmp = tmp->next;
5613 i++;
5614 }
5615 }
5616 valuePush(ctxt, xmlXPathNewFloat((double) i));
5617 }
5618 }
Owen Taylor3473f882001-02-23 17:55:21 +00005619 xmlXPathFreeObject(cur);
5620}
5621
5622/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005623 * xmlXPathGetElementsByIds:
5624 * @doc: the document
5625 * @ids: a whitespace separated list of IDs
5626 *
5627 * Selects elements by their unique ID.
5628 *
5629 * Returns a node-set of selected elements.
5630 */
5631static xmlNodeSetPtr
5632xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5633 xmlNodeSetPtr ret;
5634 const xmlChar *cur = ids;
5635 xmlChar *ID;
5636 xmlAttrPtr attr;
5637 xmlNodePtr elem = NULL;
5638
5639 ret = xmlXPathNodeSetCreate(NULL);
5640
5641 while (IS_BLANK(*cur)) cur++;
5642 while (*cur != 0) {
5643 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
5644 (*cur == '.') || (*cur == '-') ||
5645 (*cur == '_') || (*cur == ':') ||
5646 (IS_COMBINING(*cur)) ||
5647 (IS_EXTENDER(*cur)))
5648 cur++;
5649
5650 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
5651
5652 ID = xmlStrndup(ids, cur - ids);
5653 attr = xmlGetID(doc, ID);
5654 if (attr != NULL) {
5655 elem = attr->parent;
5656 xmlXPathNodeSetAdd(ret, elem);
5657 }
5658 if (ID != NULL)
5659 xmlFree(ID);
5660
5661 while (IS_BLANK(*cur)) cur++;
5662 ids = cur;
5663 }
5664 return(ret);
5665}
5666
5667/**
Owen Taylor3473f882001-02-23 17:55:21 +00005668 * xmlXPathIdFunction:
5669 * @ctxt: the XPath Parser context
5670 * @nargs: the number of arguments
5671 *
5672 * Implement the id() XPath function
5673 * node-set id(object)
5674 * The id function selects elements by their unique ID
5675 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
5676 * then the result is the union of the result of applying id to the
5677 * string value of each of the nodes in the argument node-set. When the
5678 * argument to id is of any other type, the argument is converted to a
5679 * string as if by a call to the string function; the string is split
5680 * into a whitespace-separated list of tokens (whitespace is any sequence
5681 * of characters matching the production S); the result is a node-set
5682 * containing the elements in the same document as the context node that
5683 * have a unique ID equal to any of the tokens in the list.
5684 */
5685void
5686xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005687 xmlChar *tokens;
5688 xmlNodeSetPtr ret;
5689 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00005690
5691 CHECK_ARITY(1);
5692 obj = valuePop(ctxt);
5693 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
5694 if (obj->type == XPATH_NODESET) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005695 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00005696 int i;
5697
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005698 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005699
Daniel Veillard911f49a2001-04-07 15:39:35 +00005700 if (obj->nodesetval != NULL) {
5701 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005702 tokens =
5703 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
5704 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
5705 ret = xmlXPathNodeSetMerge(ret, ns);
5706 xmlXPathFreeNodeSet(ns);
5707 if (tokens != NULL)
5708 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00005709 }
Owen Taylor3473f882001-02-23 17:55:21 +00005710 }
5711
5712 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005713 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005714 return;
5715 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005716 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00005717
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005718 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
5719 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005720
Owen Taylor3473f882001-02-23 17:55:21 +00005721 xmlXPathFreeObject(obj);
5722 return;
5723}
5724
5725/**
5726 * xmlXPathLocalNameFunction:
5727 * @ctxt: the XPath Parser context
5728 * @nargs: the number of arguments
5729 *
5730 * Implement the local-name() XPath function
5731 * string local-name(node-set?)
5732 * The local-name function returns a string containing the local part
5733 * of the name of the node in the argument node-set that is first in
5734 * document order. If the node-set is empty or the first node has no
5735 * name, an empty string is returned. If the argument is omitted it
5736 * defaults to the context node.
5737 */
5738void
5739xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5740 xmlXPathObjectPtr cur;
5741
5742 if (nargs == 0) {
5743 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5744 nargs = 1;
5745 }
5746
5747 CHECK_ARITY(1);
5748 if ((ctxt->value == NULL) ||
5749 ((ctxt->value->type != XPATH_NODESET) &&
5750 (ctxt->value->type != XPATH_XSLT_TREE)))
5751 XP_ERROR(XPATH_INVALID_TYPE);
5752 cur = valuePop(ctxt);
5753
Daniel Veillard911f49a2001-04-07 15:39:35 +00005754 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005755 valuePush(ctxt, xmlXPathNewCString(""));
5756 } else {
5757 int i = 0; /* Should be first in document order !!!!! */
5758 switch (cur->nodesetval->nodeTab[i]->type) {
5759 case XML_ELEMENT_NODE:
5760 case XML_ATTRIBUTE_NODE:
5761 case XML_PI_NODE:
5762 valuePush(ctxt,
5763 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
5764 break;
5765 case XML_NAMESPACE_DECL:
5766 valuePush(ctxt, xmlXPathNewString(
5767 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
5768 break;
5769 default:
5770 valuePush(ctxt, xmlXPathNewCString(""));
5771 }
5772 }
5773 xmlXPathFreeObject(cur);
5774}
5775
5776/**
5777 * xmlXPathNamespaceURIFunction:
5778 * @ctxt: the XPath Parser context
5779 * @nargs: the number of arguments
5780 *
5781 * Implement the namespace-uri() XPath function
5782 * string namespace-uri(node-set?)
5783 * The namespace-uri function returns a string containing the
5784 * namespace URI of the expanded name of the node in the argument
5785 * node-set that is first in document order. If the node-set is empty,
5786 * the first node has no name, or the expanded name has no namespace
5787 * URI, an empty string is returned. If the argument is omitted it
5788 * defaults to the context node.
5789 */
5790void
5791xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5792 xmlXPathObjectPtr cur;
5793
5794 if (nargs == 0) {
5795 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5796 nargs = 1;
5797 }
5798 CHECK_ARITY(1);
5799 if ((ctxt->value == NULL) ||
5800 ((ctxt->value->type != XPATH_NODESET) &&
5801 (ctxt->value->type != XPATH_XSLT_TREE)))
5802 XP_ERROR(XPATH_INVALID_TYPE);
5803 cur = valuePop(ctxt);
5804
Daniel Veillard911f49a2001-04-07 15:39:35 +00005805 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005806 valuePush(ctxt, xmlXPathNewCString(""));
5807 } else {
5808 int i = 0; /* Should be first in document order !!!!! */
5809 switch (cur->nodesetval->nodeTab[i]->type) {
5810 case XML_ELEMENT_NODE:
5811 case XML_ATTRIBUTE_NODE:
5812 if (cur->nodesetval->nodeTab[i]->ns == NULL)
5813 valuePush(ctxt, xmlXPathNewCString(""));
5814 else
5815 valuePush(ctxt, xmlXPathNewString(
5816 cur->nodesetval->nodeTab[i]->ns->href));
5817 break;
5818 default:
5819 valuePush(ctxt, xmlXPathNewCString(""));
5820 }
5821 }
5822 xmlXPathFreeObject(cur);
5823}
5824
5825/**
5826 * xmlXPathNameFunction:
5827 * @ctxt: the XPath Parser context
5828 * @nargs: the number of arguments
5829 *
5830 * Implement the name() XPath function
5831 * string name(node-set?)
5832 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005833 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00005834 * order. The QName must represent the name with respect to the namespace
5835 * declarations in effect on the node whose name is being represented.
5836 * Typically, this will be the form in which the name occurred in the XML
5837 * source. This need not be the case if there are namespace declarations
5838 * in effect on the node that associate multiple prefixes with the same
5839 * namespace. However, an implementation may include information about
5840 * the original prefix in its representation of nodes; in this case, an
5841 * implementation can ensure that the returned string is always the same
5842 * as the QName used in the XML source. If the argument it omitted it
5843 * defaults to the context node.
5844 * Libxml keep the original prefix so the "real qualified name" used is
5845 * returned.
5846 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005847static void
Daniel Veillard04383752001-07-08 14:27:15 +00005848xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
5849{
Owen Taylor3473f882001-02-23 17:55:21 +00005850 xmlXPathObjectPtr cur;
5851
5852 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00005853 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5854 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00005855 }
5856
5857 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00005858 if ((ctxt->value == NULL) ||
5859 ((ctxt->value->type != XPATH_NODESET) &&
5860 (ctxt->value->type != XPATH_XSLT_TREE)))
5861 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00005862 cur = valuePop(ctxt);
5863
Daniel Veillard911f49a2001-04-07 15:39:35 +00005864 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00005865 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00005866 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00005867 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005868
Daniel Veillard04383752001-07-08 14:27:15 +00005869 switch (cur->nodesetval->nodeTab[i]->type) {
5870 case XML_ELEMENT_NODE:
5871 case XML_ATTRIBUTE_NODE:
5872 if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
5873 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL))
5874 valuePush(ctxt,
5875 xmlXPathNewString(cur->nodesetval->
5876 nodeTab[i]->name));
5877
5878 else {
5879 char name[2000];
5880
5881 snprintf(name, sizeof(name), "%s:%s",
5882 (char *) cur->nodesetval->nodeTab[i]->ns->
5883 prefix,
5884 (char *) cur->nodesetval->nodeTab[i]->name);
5885 name[sizeof(name) - 1] = 0;
5886 valuePush(ctxt, xmlXPathNewCString(name));
5887 }
5888 break;
5889 default:
5890 valuePush(ctxt,
5891 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
5892 xmlXPathLocalNameFunction(ctxt, 1);
5893 }
Owen Taylor3473f882001-02-23 17:55:21 +00005894 }
5895 xmlXPathFreeObject(cur);
5896}
5897
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005898
5899/**
Owen Taylor3473f882001-02-23 17:55:21 +00005900 * xmlXPathStringFunction:
5901 * @ctxt: the XPath Parser context
5902 * @nargs: the number of arguments
5903 *
5904 * Implement the string() XPath function
5905 * string string(object?)
5906 * he string function converts an object to a string as follows:
5907 * - A node-set is converted to a string by returning the value of
5908 * the node in the node-set that is first in document order.
5909 * If the node-set is empty, an empty string is returned.
5910 * - A number is converted to a string as follows
5911 * + NaN is converted to the string NaN
5912 * + positive zero is converted to the string 0
5913 * + negative zero is converted to the string 0
5914 * + positive infinity is converted to the string Infinity
5915 * + negative infinity is converted to the string -Infinity
5916 * + if the number is an integer, the number is represented in
5917 * decimal form as a Number with no decimal point and no leading
5918 * zeros, preceded by a minus sign (-) if the number is negative
5919 * + otherwise, the number is represented in decimal form as a
5920 * Number including a decimal point with at least one digit
5921 * before the decimal point and at least one digit after the
5922 * decimal point, preceded by a minus sign (-) if the number
5923 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005924 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00005925 * before the decimal point; beyond the one required digit
5926 * after the decimal point there must be as many, but only as
5927 * many, more digits as are needed to uniquely distinguish the
5928 * number from all other IEEE 754 numeric values.
5929 * - The boolean false value is converted to the string false.
5930 * The boolean true value is converted to the string true.
5931 *
5932 * If the argument is omitted, it defaults to a node-set with the
5933 * context node as its only member.
5934 */
5935void
5936xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5937 xmlXPathObjectPtr cur;
5938
5939 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005940 valuePush(ctxt,
5941 xmlXPathWrapString(
5942 xmlXPathCastNodeToString(ctxt->context->node)));
5943 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005944 }
5945
5946 CHECK_ARITY(1);
5947 cur = valuePop(ctxt);
5948 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005949 cur = xmlXPathConvertString(cur);
5950 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005951}
5952
5953/**
5954 * xmlXPathStringLengthFunction:
5955 * @ctxt: the XPath Parser context
5956 * @nargs: the number of arguments
5957 *
5958 * Implement the string-length() XPath function
5959 * number string-length(string?)
5960 * The string-length returns the number of characters in the string
5961 * (see [3.6 Strings]). If the argument is omitted, it defaults to
5962 * the context node converted to a string, in other words the value
5963 * of the context node.
5964 */
5965void
5966xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5967 xmlXPathObjectPtr cur;
5968
5969 if (nargs == 0) {
5970 if (ctxt->context->node == NULL) {
5971 valuePush(ctxt, xmlXPathNewFloat(0));
5972 } else {
5973 xmlChar *content;
5974
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005975 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00005976 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00005977 xmlFree(content);
5978 }
5979 return;
5980 }
5981 CHECK_ARITY(1);
5982 CAST_TO_STRING;
5983 CHECK_TYPE(XPATH_STRING);
5984 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00005985 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00005986 xmlXPathFreeObject(cur);
5987}
5988
5989/**
5990 * xmlXPathConcatFunction:
5991 * @ctxt: the XPath Parser context
5992 * @nargs: the number of arguments
5993 *
5994 * Implement the concat() XPath function
5995 * string concat(string, string, string*)
5996 * The concat function returns the concatenation of its arguments.
5997 */
5998void
5999xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6000 xmlXPathObjectPtr cur, newobj;
6001 xmlChar *tmp;
6002
6003 if (nargs < 2) {
6004 CHECK_ARITY(2);
6005 }
6006
6007 CAST_TO_STRING;
6008 cur = valuePop(ctxt);
6009 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6010 xmlXPathFreeObject(cur);
6011 return;
6012 }
6013 nargs--;
6014
6015 while (nargs > 0) {
6016 CAST_TO_STRING;
6017 newobj = valuePop(ctxt);
6018 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6019 xmlXPathFreeObject(newobj);
6020 xmlXPathFreeObject(cur);
6021 XP_ERROR(XPATH_INVALID_TYPE);
6022 }
6023 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6024 newobj->stringval = cur->stringval;
6025 cur->stringval = tmp;
6026
6027 xmlXPathFreeObject(newobj);
6028 nargs--;
6029 }
6030 valuePush(ctxt, cur);
6031}
6032
6033/**
6034 * xmlXPathContainsFunction:
6035 * @ctxt: the XPath Parser context
6036 * @nargs: the number of arguments
6037 *
6038 * Implement the contains() XPath function
6039 * boolean contains(string, string)
6040 * The contains function returns true if the first argument string
6041 * contains the second argument string, and otherwise returns false.
6042 */
6043void
6044xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6045 xmlXPathObjectPtr hay, needle;
6046
6047 CHECK_ARITY(2);
6048 CAST_TO_STRING;
6049 CHECK_TYPE(XPATH_STRING);
6050 needle = valuePop(ctxt);
6051 CAST_TO_STRING;
6052 hay = valuePop(ctxt);
6053 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6054 xmlXPathFreeObject(hay);
6055 xmlXPathFreeObject(needle);
6056 XP_ERROR(XPATH_INVALID_TYPE);
6057 }
6058 if (xmlStrstr(hay->stringval, needle->stringval))
6059 valuePush(ctxt, xmlXPathNewBoolean(1));
6060 else
6061 valuePush(ctxt, xmlXPathNewBoolean(0));
6062 xmlXPathFreeObject(hay);
6063 xmlXPathFreeObject(needle);
6064}
6065
6066/**
6067 * xmlXPathStartsWithFunction:
6068 * @ctxt: the XPath Parser context
6069 * @nargs: the number of arguments
6070 *
6071 * Implement the starts-with() XPath function
6072 * boolean starts-with(string, string)
6073 * The starts-with function returns true if the first argument string
6074 * starts with the second argument string, and otherwise returns false.
6075 */
6076void
6077xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6078 xmlXPathObjectPtr hay, needle;
6079 int n;
6080
6081 CHECK_ARITY(2);
6082 CAST_TO_STRING;
6083 CHECK_TYPE(XPATH_STRING);
6084 needle = valuePop(ctxt);
6085 CAST_TO_STRING;
6086 hay = valuePop(ctxt);
6087 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6088 xmlXPathFreeObject(hay);
6089 xmlXPathFreeObject(needle);
6090 XP_ERROR(XPATH_INVALID_TYPE);
6091 }
6092 n = xmlStrlen(needle->stringval);
6093 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6094 valuePush(ctxt, xmlXPathNewBoolean(0));
6095 else
6096 valuePush(ctxt, xmlXPathNewBoolean(1));
6097 xmlXPathFreeObject(hay);
6098 xmlXPathFreeObject(needle);
6099}
6100
6101/**
6102 * xmlXPathSubstringFunction:
6103 * @ctxt: the XPath Parser context
6104 * @nargs: the number of arguments
6105 *
6106 * Implement the substring() XPath function
6107 * string substring(string, number, number?)
6108 * The substring function returns the substring of the first argument
6109 * starting at the position specified in the second argument with
6110 * length specified in the third argument. For example,
6111 * substring("12345",2,3) returns "234". If the third argument is not
6112 * specified, it returns the substring starting at the position specified
6113 * in the second argument and continuing to the end of the string. For
6114 * example, substring("12345",2) returns "2345". More precisely, each
6115 * character in the string (see [3.6 Strings]) is considered to have a
6116 * numeric position: the position of the first character is 1, the position
6117 * of the second character is 2 and so on. The returned substring contains
6118 * those characters for which the position of the character is greater than
6119 * or equal to the second argument and, if the third argument is specified,
6120 * less than the sum of the second and third arguments; the comparisons
6121 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6122 * - substring("12345", 1.5, 2.6) returns "234"
6123 * - substring("12345", 0, 3) returns "12"
6124 * - substring("12345", 0 div 0, 3) returns ""
6125 * - substring("12345", 1, 0 div 0) returns ""
6126 * - substring("12345", -42, 1 div 0) returns "12345"
6127 * - substring("12345", -1 div 0, 1 div 0) returns ""
6128 */
6129void
6130xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6131 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006132 double le=0, in;
6133 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006134 xmlChar *ret;
6135
Owen Taylor3473f882001-02-23 17:55:21 +00006136 if (nargs < 2) {
6137 CHECK_ARITY(2);
6138 }
6139 if (nargs > 3) {
6140 CHECK_ARITY(3);
6141 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006142 /*
6143 * take care of possible last (position) argument
6144 */
Owen Taylor3473f882001-02-23 17:55:21 +00006145 if (nargs == 3) {
6146 CAST_TO_NUMBER;
6147 CHECK_TYPE(XPATH_NUMBER);
6148 len = valuePop(ctxt);
6149 le = len->floatval;
6150 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006151 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006152
Owen Taylor3473f882001-02-23 17:55:21 +00006153 CAST_TO_NUMBER;
6154 CHECK_TYPE(XPATH_NUMBER);
6155 start = valuePop(ctxt);
6156 in = start->floatval;
6157 xmlXPathFreeObject(start);
6158 CAST_TO_STRING;
6159 CHECK_TYPE(XPATH_STRING);
6160 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006161 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006162
Daniel Veillard97ac1312001-05-30 19:14:17 +00006163 /*
6164 * If last pos not present, calculate last position
6165 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006166 if (nargs != 3) {
6167 le = (double)m;
6168 if (in < 1.0)
6169 in = 1.0;
6170 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006171
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006172 /* Need to check for the special cases where either
6173 * the index is NaN, the length is NaN, or both
6174 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00006175 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006176 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006177 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00006178 * To meet the requirements of the spec, the arguments
6179 * must be converted to integer format before
6180 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006181 *
Daniel Veillard9e412302002-06-10 15:59:44 +00006182 * First we go to integer form, rounding up
6183 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006184 */
6185 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00006186 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00006187
Daniel Veillard9e412302002-06-10 15:59:44 +00006188 if (xmlXPathIsInf(le) == 1) {
6189 l = m;
6190 if (i < 1)
6191 i = 1;
6192 }
6193 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
6194 l = 0;
6195 else {
6196 l = (int) le;
6197 if (((double)l)+0.5 <= le) l++;
6198 }
6199
6200 /* Now we normalize inidices */
6201 i -= 1;
6202 l += i;
6203 if (i < 0)
6204 i = 0;
6205 if (l > m)
6206 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00006207
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006208 /* number of chars to copy */
6209 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00006210
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006211 ret = xmlUTF8Strsub(str->stringval, i, l);
6212 }
6213 else {
6214 ret = NULL;
6215 }
6216
Owen Taylor3473f882001-02-23 17:55:21 +00006217 if (ret == NULL)
6218 valuePush(ctxt, xmlXPathNewCString(""));
6219 else {
6220 valuePush(ctxt, xmlXPathNewString(ret));
6221 xmlFree(ret);
6222 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006223
Owen Taylor3473f882001-02-23 17:55:21 +00006224 xmlXPathFreeObject(str);
6225}
6226
6227/**
6228 * xmlXPathSubstringBeforeFunction:
6229 * @ctxt: the XPath Parser context
6230 * @nargs: the number of arguments
6231 *
6232 * Implement the substring-before() XPath function
6233 * string substring-before(string, string)
6234 * The substring-before function returns the substring of the first
6235 * argument string that precedes the first occurrence of the second
6236 * argument string in the first argument string, or the empty string
6237 * if the first argument string does not contain the second argument
6238 * string. For example, substring-before("1999/04/01","/") returns 1999.
6239 */
6240void
6241xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6242 xmlXPathObjectPtr str;
6243 xmlXPathObjectPtr find;
6244 xmlBufferPtr target;
6245 const xmlChar *point;
6246 int offset;
6247
6248 CHECK_ARITY(2);
6249 CAST_TO_STRING;
6250 find = valuePop(ctxt);
6251 CAST_TO_STRING;
6252 str = valuePop(ctxt);
6253
6254 target = xmlBufferCreate();
6255 if (target) {
6256 point = xmlStrstr(str->stringval, find->stringval);
6257 if (point) {
6258 offset = (int)(point - str->stringval);
6259 xmlBufferAdd(target, str->stringval, offset);
6260 }
6261 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6262 xmlBufferFree(target);
6263 }
6264
6265 xmlXPathFreeObject(str);
6266 xmlXPathFreeObject(find);
6267}
6268
6269/**
6270 * xmlXPathSubstringAfterFunction:
6271 * @ctxt: the XPath Parser context
6272 * @nargs: the number of arguments
6273 *
6274 * Implement the substring-after() XPath function
6275 * string substring-after(string, string)
6276 * The substring-after function returns the substring of the first
6277 * argument string that follows the first occurrence of the second
6278 * argument string in the first argument string, or the empty stringi
6279 * if the first argument string does not contain the second argument
6280 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6281 * and substring-after("1999/04/01","19") returns 99/04/01.
6282 */
6283void
6284xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6285 xmlXPathObjectPtr str;
6286 xmlXPathObjectPtr find;
6287 xmlBufferPtr target;
6288 const xmlChar *point;
6289 int offset;
6290
6291 CHECK_ARITY(2);
6292 CAST_TO_STRING;
6293 find = valuePop(ctxt);
6294 CAST_TO_STRING;
6295 str = valuePop(ctxt);
6296
6297 target = xmlBufferCreate();
6298 if (target) {
6299 point = xmlStrstr(str->stringval, find->stringval);
6300 if (point) {
6301 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6302 xmlBufferAdd(target, &str->stringval[offset],
6303 xmlStrlen(str->stringval) - offset);
6304 }
6305 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6306 xmlBufferFree(target);
6307 }
6308
6309 xmlXPathFreeObject(str);
6310 xmlXPathFreeObject(find);
6311}
6312
6313/**
6314 * xmlXPathNormalizeFunction:
6315 * @ctxt: the XPath Parser context
6316 * @nargs: the number of arguments
6317 *
6318 * Implement the normalize-space() XPath function
6319 * string normalize-space(string?)
6320 * The normalize-space function returns the argument string with white
6321 * space normalized by stripping leading and trailing whitespace
6322 * and replacing sequences of whitespace characters by a single
6323 * space. Whitespace characters are the same allowed by the S production
6324 * in XML. If the argument is omitted, it defaults to the context
6325 * node converted to a string, in other words the value of the context node.
6326 */
6327void
6328xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6329 xmlXPathObjectPtr obj = NULL;
6330 xmlChar *source = NULL;
6331 xmlBufferPtr target;
6332 xmlChar blank;
6333
6334 if (nargs == 0) {
6335 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006336 valuePush(ctxt,
6337 xmlXPathWrapString(
6338 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006339 nargs = 1;
6340 }
6341
6342 CHECK_ARITY(1);
6343 CAST_TO_STRING;
6344 CHECK_TYPE(XPATH_STRING);
6345 obj = valuePop(ctxt);
6346 source = obj->stringval;
6347
6348 target = xmlBufferCreate();
6349 if (target && source) {
6350
6351 /* Skip leading whitespaces */
6352 while (IS_BLANK(*source))
6353 source++;
6354
6355 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6356 blank = 0;
6357 while (*source) {
6358 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006359 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006360 } else {
6361 if (blank) {
6362 xmlBufferAdd(target, &blank, 1);
6363 blank = 0;
6364 }
6365 xmlBufferAdd(target, source, 1);
6366 }
6367 source++;
6368 }
6369
6370 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6371 xmlBufferFree(target);
6372 }
6373 xmlXPathFreeObject(obj);
6374}
6375
6376/**
6377 * xmlXPathTranslateFunction:
6378 * @ctxt: the XPath Parser context
6379 * @nargs: the number of arguments
6380 *
6381 * Implement the translate() XPath function
6382 * string translate(string, string, string)
6383 * The translate function returns the first argument string with
6384 * occurrences of characters in the second argument string replaced
6385 * by the character at the corresponding position in the third argument
6386 * string. For example, translate("bar","abc","ABC") returns the string
6387 * BAr. If there is a character in the second argument string with no
6388 * character at a corresponding position in the third argument string
6389 * (because the second argument string is longer than the third argument
6390 * string), then occurrences of that character in the first argument
6391 * string are removed. For example, translate("--aaa--","abc-","ABC")
6392 * returns "AAA". If a character occurs more than once in second
6393 * argument string, then the first occurrence determines the replacement
6394 * character. If the third argument string is longer than the second
6395 * argument string, then excess characters are ignored.
6396 */
6397void
6398xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006399 xmlXPathObjectPtr str;
6400 xmlXPathObjectPtr from;
6401 xmlXPathObjectPtr to;
6402 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006403 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006404 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006405 xmlChar *point;
6406 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006407
Daniel Veillarde043ee12001-04-16 14:08:07 +00006408 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006409
Daniel Veillarde043ee12001-04-16 14:08:07 +00006410 CAST_TO_STRING;
6411 to = valuePop(ctxt);
6412 CAST_TO_STRING;
6413 from = valuePop(ctxt);
6414 CAST_TO_STRING;
6415 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006416
Daniel Veillarde043ee12001-04-16 14:08:07 +00006417 target = xmlBufferCreate();
6418 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006419 max = xmlUTF8Strlen(to->stringval);
6420 for (cptr = str->stringval; (ch=*cptr); ) {
6421 offset = xmlUTF8Strloc(from->stringval, cptr);
6422 if (offset >= 0) {
6423 if (offset < max) {
6424 point = xmlUTF8Strpos(to->stringval, offset);
6425 if (point)
6426 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6427 }
6428 } else
6429 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6430
6431 /* Step to next character in input */
6432 cptr++;
6433 if ( ch & 0x80 ) {
6434 /* if not simple ascii, verify proper format */
6435 if ( (ch & 0xc0) != 0xc0 ) {
6436 xmlGenericError(xmlGenericErrorContext,
6437 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6438 break;
6439 }
6440 /* then skip over remaining bytes for this char */
6441 while ( (ch <<= 1) & 0x80 )
6442 if ( (*cptr++ & 0xc0) != 0x80 ) {
6443 xmlGenericError(xmlGenericErrorContext,
6444 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6445 break;
6446 }
6447 if (ch & 0x80) /* must have had error encountered */
6448 break;
6449 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006450 }
Owen Taylor3473f882001-02-23 17:55:21 +00006451 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006452 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6453 xmlBufferFree(target);
6454 xmlXPathFreeObject(str);
6455 xmlXPathFreeObject(from);
6456 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006457}
6458
6459/**
6460 * xmlXPathBooleanFunction:
6461 * @ctxt: the XPath Parser context
6462 * @nargs: the number of arguments
6463 *
6464 * Implement the boolean() XPath function
6465 * boolean boolean(object)
6466 * he boolean function converts its argument to a boolean as follows:
6467 * - a number is true if and only if it is neither positive or
6468 * negative zero nor NaN
6469 * - a node-set is true if and only if it is non-empty
6470 * - a string is true if and only if its length is non-zero
6471 */
6472void
6473xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6474 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006475
6476 CHECK_ARITY(1);
6477 cur = valuePop(ctxt);
6478 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006479 cur = xmlXPathConvertBoolean(cur);
6480 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006481}
6482
6483/**
6484 * xmlXPathNotFunction:
6485 * @ctxt: the XPath Parser context
6486 * @nargs: the number of arguments
6487 *
6488 * Implement the not() XPath function
6489 * boolean not(boolean)
6490 * The not function returns true if its argument is false,
6491 * and false otherwise.
6492 */
6493void
6494xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6495 CHECK_ARITY(1);
6496 CAST_TO_BOOLEAN;
6497 CHECK_TYPE(XPATH_BOOLEAN);
6498 ctxt->value->boolval = ! ctxt->value->boolval;
6499}
6500
6501/**
6502 * xmlXPathTrueFunction:
6503 * @ctxt: the XPath Parser context
6504 * @nargs: the number of arguments
6505 *
6506 * Implement the true() XPath function
6507 * boolean true()
6508 */
6509void
6510xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6511 CHECK_ARITY(0);
6512 valuePush(ctxt, xmlXPathNewBoolean(1));
6513}
6514
6515/**
6516 * xmlXPathFalseFunction:
6517 * @ctxt: the XPath Parser context
6518 * @nargs: the number of arguments
6519 *
6520 * Implement the false() XPath function
6521 * boolean false()
6522 */
6523void
6524xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6525 CHECK_ARITY(0);
6526 valuePush(ctxt, xmlXPathNewBoolean(0));
6527}
6528
6529/**
6530 * xmlXPathLangFunction:
6531 * @ctxt: the XPath Parser context
6532 * @nargs: the number of arguments
6533 *
6534 * Implement the lang() XPath function
6535 * boolean lang(string)
6536 * The lang function returns true or false depending on whether the
6537 * language of the context node as specified by xml:lang attributes
6538 * is the same as or is a sublanguage of the language specified by
6539 * the argument string. The language of the context node is determined
6540 * by the value of the xml:lang attribute on the context node, or, if
6541 * the context node has no xml:lang attribute, by the value of the
6542 * xml:lang attribute on the nearest ancestor of the context node that
6543 * has an xml:lang attribute. If there is no such attribute, then lang
6544 * returns false. If there is such an attribute, then lang returns
6545 * true if the attribute value is equal to the argument ignoring case,
6546 * or if there is some suffix starting with - such that the attribute
6547 * value is equal to the argument ignoring that suffix of the attribute
6548 * value and ignoring case.
6549 */
6550void
6551xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6552 xmlXPathObjectPtr val;
6553 const xmlChar *theLang;
6554 const xmlChar *lang;
6555 int ret = 0;
6556 int i;
6557
6558 CHECK_ARITY(1);
6559 CAST_TO_STRING;
6560 CHECK_TYPE(XPATH_STRING);
6561 val = valuePop(ctxt);
6562 lang = val->stringval;
6563 theLang = xmlNodeGetLang(ctxt->context->node);
6564 if ((theLang != NULL) && (lang != NULL)) {
6565 for (i = 0;lang[i] != 0;i++)
6566 if (toupper(lang[i]) != toupper(theLang[i]))
6567 goto not_equal;
6568 ret = 1;
6569 }
6570not_equal:
6571 xmlXPathFreeObject(val);
6572 valuePush(ctxt, xmlXPathNewBoolean(ret));
6573}
6574
6575/**
6576 * xmlXPathNumberFunction:
6577 * @ctxt: the XPath Parser context
6578 * @nargs: the number of arguments
6579 *
6580 * Implement the number() XPath function
6581 * number number(object?)
6582 */
6583void
6584xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6585 xmlXPathObjectPtr cur;
6586 double res;
6587
6588 if (nargs == 0) {
6589 if (ctxt->context->node == NULL) {
6590 valuePush(ctxt, xmlXPathNewFloat(0.0));
6591 } else {
6592 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6593
6594 res = xmlXPathStringEvalNumber(content);
6595 valuePush(ctxt, xmlXPathNewFloat(res));
6596 xmlFree(content);
6597 }
6598 return;
6599 }
6600
6601 CHECK_ARITY(1);
6602 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006603 cur = xmlXPathConvertNumber(cur);
6604 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006605}
6606
6607/**
6608 * xmlXPathSumFunction:
6609 * @ctxt: the XPath Parser context
6610 * @nargs: the number of arguments
6611 *
6612 * Implement the sum() XPath function
6613 * number sum(node-set)
6614 * The sum function returns the sum of the values of the nodes in
6615 * the argument node-set.
6616 */
6617void
6618xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6619 xmlXPathObjectPtr cur;
6620 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006621 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00006622
6623 CHECK_ARITY(1);
6624 if ((ctxt->value == NULL) ||
6625 ((ctxt->value->type != XPATH_NODESET) &&
6626 (ctxt->value->type != XPATH_XSLT_TREE)))
6627 XP_ERROR(XPATH_INVALID_TYPE);
6628 cur = valuePop(ctxt);
6629
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006630 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006631 valuePush(ctxt, xmlXPathNewFloat(0.0));
6632 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006633 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
6634 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006635 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006636 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00006637 }
6638 xmlXPathFreeObject(cur);
6639}
6640
6641/**
6642 * xmlXPathFloorFunction:
6643 * @ctxt: the XPath Parser context
6644 * @nargs: the number of arguments
6645 *
6646 * Implement the floor() XPath function
6647 * number floor(number)
6648 * The floor function returns the largest (closest to positive infinity)
6649 * number that is not greater than the argument and that is an integer.
6650 */
6651void
6652xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006653 double f;
6654
Owen Taylor3473f882001-02-23 17:55:21 +00006655 CHECK_ARITY(1);
6656 CAST_TO_NUMBER;
6657 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006658
6659 f = (double)((int) ctxt->value->floatval);
6660 if (f != ctxt->value->floatval) {
6661 if (ctxt->value->floatval > 0)
6662 ctxt->value->floatval = f;
6663 else
6664 ctxt->value->floatval = f - 1;
6665 }
Owen Taylor3473f882001-02-23 17:55:21 +00006666}
6667
6668/**
6669 * xmlXPathCeilingFunction:
6670 * @ctxt: the XPath Parser context
6671 * @nargs: the number of arguments
6672 *
6673 * Implement the ceiling() XPath function
6674 * number ceiling(number)
6675 * The ceiling function returns the smallest (closest to negative infinity)
6676 * number that is not less than the argument and that is an integer.
6677 */
6678void
6679xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6680 double f;
6681
6682 CHECK_ARITY(1);
6683 CAST_TO_NUMBER;
6684 CHECK_TYPE(XPATH_NUMBER);
6685
6686#if 0
6687 ctxt->value->floatval = ceil(ctxt->value->floatval);
6688#else
6689 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006690 if (f != ctxt->value->floatval) {
6691 if (ctxt->value->floatval > 0)
6692 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00006693 else {
6694 if (ctxt->value->floatval < 0 && f == 0)
6695 ctxt->value->floatval = xmlXPathNZERO;
6696 else
6697 ctxt->value->floatval = f;
6698 }
6699
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006700 }
Owen Taylor3473f882001-02-23 17:55:21 +00006701#endif
6702}
6703
6704/**
6705 * xmlXPathRoundFunction:
6706 * @ctxt: the XPath Parser context
6707 * @nargs: the number of arguments
6708 *
6709 * Implement the round() XPath function
6710 * number round(number)
6711 * The round function returns the number that is closest to the
6712 * argument and that is an integer. If there are two such numbers,
6713 * then the one that is even is returned.
6714 */
6715void
6716xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6717 double f;
6718
6719 CHECK_ARITY(1);
6720 CAST_TO_NUMBER;
6721 CHECK_TYPE(XPATH_NUMBER);
6722
Daniel Veillardcda96922001-08-21 10:56:31 +00006723 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
6724 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
6725 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00006726 (ctxt->value->floatval == 0.0))
6727 return;
6728
Owen Taylor3473f882001-02-23 17:55:21 +00006729 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006730 if (ctxt->value->floatval < 0) {
6731 if (ctxt->value->floatval < f - 0.5)
6732 ctxt->value->floatval = f - 1;
6733 else
6734 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00006735 if (ctxt->value->floatval == 0)
6736 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006737 } else {
6738 if (ctxt->value->floatval < f + 0.5)
6739 ctxt->value->floatval = f;
6740 else
6741 ctxt->value->floatval = f + 1;
6742 }
Owen Taylor3473f882001-02-23 17:55:21 +00006743}
6744
6745/************************************************************************
6746 * *
6747 * The Parser *
6748 * *
6749 ************************************************************************/
6750
6751/*
6752 * a couple of forward declarations since we use a recursive call based
6753 * implementation.
6754 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006755static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006756static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006757static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006758#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006759static void xmlXPathCompRelLocationPath(xmlXPathParserContextPtr ctxt);
6760#define xmlXPathCompRelativeLocationPath xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00006761#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006762static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006763#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00006764static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
6765 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00006766
6767/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00006768 * xmlXPathCurrentChar:
6769 * @ctxt: the XPath parser context
6770 * @cur: pointer to the beginning of the char
6771 * @len: pointer to the length of the char read
6772 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006773 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00006774 * bytes in the input buffer.
6775 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006776 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00006777 */
6778
6779static int
6780xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
6781 unsigned char c;
6782 unsigned int val;
6783 const xmlChar *cur;
6784
6785 if (ctxt == NULL)
6786 return(0);
6787 cur = ctxt->cur;
6788
6789 /*
6790 * We are supposed to handle UTF8, check it's valid
6791 * From rfc2044: encoding of the Unicode values on UTF-8:
6792 *
6793 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
6794 * 0000 0000-0000 007F 0xxxxxxx
6795 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
6796 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
6797 *
6798 * Check for the 0x110000 limit too
6799 */
6800 c = *cur;
6801 if (c & 0x80) {
6802 if ((cur[1] & 0xc0) != 0x80)
6803 goto encoding_error;
6804 if ((c & 0xe0) == 0xe0) {
6805
6806 if ((cur[2] & 0xc0) != 0x80)
6807 goto encoding_error;
6808 if ((c & 0xf0) == 0xf0) {
6809 if (((c & 0xf8) != 0xf0) ||
6810 ((cur[3] & 0xc0) != 0x80))
6811 goto encoding_error;
6812 /* 4-byte code */
6813 *len = 4;
6814 val = (cur[0] & 0x7) << 18;
6815 val |= (cur[1] & 0x3f) << 12;
6816 val |= (cur[2] & 0x3f) << 6;
6817 val |= cur[3] & 0x3f;
6818 } else {
6819 /* 3-byte code */
6820 *len = 3;
6821 val = (cur[0] & 0xf) << 12;
6822 val |= (cur[1] & 0x3f) << 6;
6823 val |= cur[2] & 0x3f;
6824 }
6825 } else {
6826 /* 2-byte code */
6827 *len = 2;
6828 val = (cur[0] & 0x1f) << 6;
6829 val |= cur[1] & 0x3f;
6830 }
6831 if (!IS_CHAR(val)) {
6832 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
6833 }
6834 return(val);
6835 } else {
6836 /* 1-byte code */
6837 *len = 1;
6838 return((int) *cur);
6839 }
6840encoding_error:
6841 /*
6842 * If we detect an UTF8 error that probably mean that the
6843 * input encoding didn't get properly advertized in the
6844 * declaration header. Report the error and switch the encoding
6845 * to ISO-Latin-1 (if you don't like this policy, just declare the
6846 * encoding !)
6847 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00006848 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00006849 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00006850}
6851
6852/**
Owen Taylor3473f882001-02-23 17:55:21 +00006853 * xmlXPathParseNCName:
6854 * @ctxt: the XPath Parser context
6855 *
6856 * parse an XML namespace non qualified name.
6857 *
6858 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
6859 *
6860 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
6861 * CombiningChar | Extender
6862 *
6863 * Returns the namespace name or NULL
6864 */
6865
6866xmlChar *
6867xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00006868 const xmlChar *in;
6869 xmlChar *ret;
6870 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006871
Daniel Veillard2156a562001-04-28 12:24:34 +00006872 /*
6873 * Accelerator for simple ASCII names
6874 */
6875 in = ctxt->cur;
6876 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6877 ((*in >= 0x41) && (*in <= 0x5A)) ||
6878 (*in == '_')) {
6879 in++;
6880 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6881 ((*in >= 0x41) && (*in <= 0x5A)) ||
6882 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00006883 (*in == '_') || (*in == '.') ||
6884 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00006885 in++;
6886 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
6887 (*in == '[') || (*in == ']') || (*in == ':') ||
6888 (*in == '@') || (*in == '*')) {
6889 count = in - ctxt->cur;
6890 if (count == 0)
6891 return(NULL);
6892 ret = xmlStrndup(ctxt->cur, count);
6893 ctxt->cur = in;
6894 return(ret);
6895 }
6896 }
6897 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00006898}
6899
Daniel Veillard2156a562001-04-28 12:24:34 +00006900
Owen Taylor3473f882001-02-23 17:55:21 +00006901/**
6902 * xmlXPathParseQName:
6903 * @ctxt: the XPath Parser context
6904 * @prefix: a xmlChar **
6905 *
6906 * parse an XML qualified name
6907 *
6908 * [NS 5] QName ::= (Prefix ':')? LocalPart
6909 *
6910 * [NS 6] Prefix ::= NCName
6911 *
6912 * [NS 7] LocalPart ::= NCName
6913 *
6914 * Returns the function returns the local part, and prefix is updated
6915 * to get the Prefix if any.
6916 */
6917
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006918static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006919xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
6920 xmlChar *ret = NULL;
6921
6922 *prefix = NULL;
6923 ret = xmlXPathParseNCName(ctxt);
6924 if (CUR == ':') {
6925 *prefix = ret;
6926 NEXT;
6927 ret = xmlXPathParseNCName(ctxt);
6928 }
6929 return(ret);
6930}
6931
6932/**
6933 * xmlXPathParseName:
6934 * @ctxt: the XPath Parser context
6935 *
6936 * parse an XML name
6937 *
6938 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
6939 * CombiningChar | Extender
6940 *
6941 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
6942 *
6943 * Returns the namespace name or NULL
6944 */
6945
6946xmlChar *
6947xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006948 const xmlChar *in;
6949 xmlChar *ret;
6950 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006951
Daniel Veillard61d80a22001-04-27 17:13:01 +00006952 /*
6953 * Accelerator for simple ASCII names
6954 */
6955 in = ctxt->cur;
6956 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6957 ((*in >= 0x41) && (*in <= 0x5A)) ||
6958 (*in == '_') || (*in == ':')) {
6959 in++;
6960 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6961 ((*in >= 0x41) && (*in <= 0x5A)) ||
6962 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00006963 (*in == '_') || (*in == '-') ||
6964 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00006965 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00006966 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006967 count = in - ctxt->cur;
6968 ret = xmlStrndup(ctxt->cur, count);
6969 ctxt->cur = in;
6970 return(ret);
6971 }
6972 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006973 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00006974}
6975
Daniel Veillard61d80a22001-04-27 17:13:01 +00006976static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00006977xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006978 xmlChar buf[XML_MAX_NAMELEN + 5];
6979 int len = 0, l;
6980 int c;
6981
6982 /*
6983 * Handler for more complex cases
6984 */
6985 c = CUR_CHAR(l);
6986 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00006987 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
6988 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00006989 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00006990 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006991 return(NULL);
6992 }
6993
6994 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
6995 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
6996 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00006997 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00006998 (IS_COMBINING(c)) ||
6999 (IS_EXTENDER(c)))) {
7000 COPY_BUF(l,buf,len,c);
7001 NEXTL(l);
7002 c = CUR_CHAR(l);
7003 if (len >= XML_MAX_NAMELEN) {
7004 /*
7005 * Okay someone managed to make a huge name, so he's ready to pay
7006 * for the processing speed.
7007 */
7008 xmlChar *buffer;
7009 int max = len * 2;
7010
7011 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
7012 if (buffer == NULL) {
7013 XP_ERROR0(XPATH_MEMORY_ERROR);
7014 }
7015 memcpy(buffer, buf, len);
7016 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7017 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007018 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007019 (IS_COMBINING(c)) ||
7020 (IS_EXTENDER(c))) {
7021 if (len + 10 > max) {
7022 max *= 2;
7023 buffer = (xmlChar *) xmlRealloc(buffer,
7024 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007025 if (buffer == NULL) {
7026 XP_ERROR0(XPATH_MEMORY_ERROR);
7027 }
7028 }
7029 COPY_BUF(l,buffer,len,c);
7030 NEXTL(l);
7031 c = CUR_CHAR(l);
7032 }
7033 buffer[len] = 0;
7034 return(buffer);
7035 }
7036 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007037 if (len == 0)
7038 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007039 return(xmlStrndup(buf, len));
7040}
Daniel Veillard3cd72402002-05-13 10:33:30 +00007041
7042#define MAX_FRAC 20
7043
7044static double my_pow10[MAX_FRAC] = {
7045 1.0, 10.0, 100.0, 1000.0, 10000.0,
7046 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7047 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7048 100000000000000.0,
7049 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
7050 1000000000000000000.0, 10000000000000000000.0
7051};
7052
Owen Taylor3473f882001-02-23 17:55:21 +00007053/**
7054 * xmlXPathStringEvalNumber:
7055 * @str: A string to scan
7056 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00007057 * [30a] Float ::= Number ('e' Digits?)?
7058 *
Owen Taylor3473f882001-02-23 17:55:21 +00007059 * [30] Number ::= Digits ('.' Digits?)?
7060 * | '.' Digits
7061 * [31] Digits ::= [0-9]+
7062 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007063 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00007064 * In complement of the Number expression, this function also handles
7065 * negative values : '-' Number.
7066 *
7067 * Returns the double value.
7068 */
7069double
7070xmlXPathStringEvalNumber(const xmlChar *str) {
7071 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00007072 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007073 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007074 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007075 int exponent = 0;
7076 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007077#ifdef __GNUC__
7078 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007079 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007080#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00007081 if (cur == NULL) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00007082 while (IS_BLANK(*cur)) cur++;
7083 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7084 return(xmlXPathNAN);
7085 }
7086 if (*cur == '-') {
7087 isneg = 1;
7088 cur++;
7089 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007090
7091#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007092 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007093 * tmp/temp is a workaround against a gcc compiler bug
7094 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007095 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007096 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007097 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007098 ret = ret * 10;
7099 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00007100 ok = 1;
7101 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00007102 temp = (double) tmp;
7103 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007104 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007105#else
Daniel Veillard7b416132002-03-07 08:36:03 +00007106 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007107 while ((*cur >= '0') && (*cur <= '9')) {
7108 ret = ret * 10 + (*cur - '0');
7109 ok = 1;
7110 cur++;
7111 }
7112#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007113
Owen Taylor3473f882001-02-23 17:55:21 +00007114 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007115 int v, frac = 0;
7116 double fraction = 0;
7117
Owen Taylor3473f882001-02-23 17:55:21 +00007118 cur++;
7119 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7120 return(xmlXPathNAN);
7121 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007122 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
7123 v = (*cur - '0');
7124 fraction = fraction * 10 + v;
7125 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007126 cur++;
7127 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007128 fraction /= my_pow10[frac];
7129 ret = ret + fraction;
7130 while ((*cur >= '0') && (*cur <= '9'))
7131 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007132 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007133 if ((*cur == 'e') || (*cur == 'E')) {
7134 cur++;
7135 if (*cur == '-') {
7136 is_exponent_negative = 1;
7137 cur++;
7138 }
7139 while ((*cur >= '0') && (*cur <= '9')) {
7140 exponent = exponent * 10 + (*cur - '0');
7141 cur++;
7142 }
7143 }
Owen Taylor3473f882001-02-23 17:55:21 +00007144 while (IS_BLANK(*cur)) cur++;
7145 if (*cur != 0) return(xmlXPathNAN);
7146 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007147 if (is_exponent_negative) exponent = -exponent;
7148 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007149 return(ret);
7150}
7151
7152/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007153 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007154 * @ctxt: the XPath Parser context
7155 *
7156 * [30] Number ::= Digits ('.' Digits?)?
7157 * | '.' Digits
7158 * [31] Digits ::= [0-9]+
7159 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007160 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007161 *
7162 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007163static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007164xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7165{
Owen Taylor3473f882001-02-23 17:55:21 +00007166 double ret = 0.0;
7167 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007168 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007169 int exponent = 0;
7170 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007171#ifdef __GNUC__
7172 unsigned long tmp = 0;
7173 double temp;
7174#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007175
7176 CHECK_ERROR;
7177 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7178 XP_ERROR(XPATH_NUMBER_ERROR);
7179 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007180#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007181 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007182 * tmp/temp is a workaround against a gcc compiler bug
7183 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007184 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007185 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007186 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007187 ret = ret * 10;
7188 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007189 ok = 1;
7190 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007191 temp = (double) tmp;
7192 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007193 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007194#else
7195 ret = 0;
7196 while ((CUR >= '0') && (CUR <= '9')) {
7197 ret = ret * 10 + (CUR - '0');
7198 ok = 1;
7199 NEXT;
7200 }
7201#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007202 if (CUR == '.') {
7203 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007204 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7205 XP_ERROR(XPATH_NUMBER_ERROR);
7206 }
7207 while ((CUR >= '0') && (CUR <= '9')) {
7208 mult /= 10;
7209 ret = ret + (CUR - '0') * mult;
7210 NEXT;
7211 }
Owen Taylor3473f882001-02-23 17:55:21 +00007212 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007213 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007214 NEXT;
7215 if (CUR == '-') {
7216 is_exponent_negative = 1;
7217 NEXT;
7218 }
7219 while ((CUR >= '0') && (CUR <= '9')) {
7220 exponent = exponent * 10 + (CUR - '0');
7221 NEXT;
7222 }
7223 if (is_exponent_negative)
7224 exponent = -exponent;
7225 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007226 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007227 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007228 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007229}
7230
7231/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007232 * xmlXPathParseLiteral:
7233 * @ctxt: the XPath Parser context
7234 *
7235 * Parse a Literal
7236 *
7237 * [29] Literal ::= '"' [^"]* '"'
7238 * | "'" [^']* "'"
7239 *
7240 * Returns the value found or NULL in case of error
7241 */
7242static xmlChar *
7243xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7244 const xmlChar *q;
7245 xmlChar *ret = NULL;
7246
7247 if (CUR == '"') {
7248 NEXT;
7249 q = CUR_PTR;
7250 while ((IS_CHAR(CUR)) && (CUR != '"'))
7251 NEXT;
7252 if (!IS_CHAR(CUR)) {
7253 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7254 } else {
7255 ret = xmlStrndup(q, CUR_PTR - q);
7256 NEXT;
7257 }
7258 } else if (CUR == '\'') {
7259 NEXT;
7260 q = CUR_PTR;
7261 while ((IS_CHAR(CUR)) && (CUR != '\''))
7262 NEXT;
7263 if (!IS_CHAR(CUR)) {
7264 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7265 } else {
7266 ret = xmlStrndup(q, CUR_PTR - q);
7267 NEXT;
7268 }
7269 } else {
7270 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7271 }
7272 return(ret);
7273}
7274
7275/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007276 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007277 * @ctxt: the XPath Parser context
7278 *
7279 * Parse a Literal and push it on the stack.
7280 *
7281 * [29] Literal ::= '"' [^"]* '"'
7282 * | "'" [^']* "'"
7283 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007284 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007285 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007286static void
7287xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007288 const xmlChar *q;
7289 xmlChar *ret = NULL;
7290
7291 if (CUR == '"') {
7292 NEXT;
7293 q = CUR_PTR;
7294 while ((IS_CHAR(CUR)) && (CUR != '"'))
7295 NEXT;
7296 if (!IS_CHAR(CUR)) {
7297 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7298 } else {
7299 ret = xmlStrndup(q, CUR_PTR - q);
7300 NEXT;
7301 }
7302 } else if (CUR == '\'') {
7303 NEXT;
7304 q = CUR_PTR;
7305 while ((IS_CHAR(CUR)) && (CUR != '\''))
7306 NEXT;
7307 if (!IS_CHAR(CUR)) {
7308 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7309 } else {
7310 ret = xmlStrndup(q, CUR_PTR - q);
7311 NEXT;
7312 }
7313 } else {
7314 XP_ERROR(XPATH_START_LITERAL_ERROR);
7315 }
7316 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007317 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7318 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007319 xmlFree(ret);
7320}
7321
7322/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007323 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007324 * @ctxt: the XPath Parser context
7325 *
7326 * Parse a VariableReference, evaluate it and push it on the stack.
7327 *
7328 * The variable bindings consist of a mapping from variable names
7329 * to variable values. The value of a variable is an object, which
7330 * of any of the types that are possible for the value of an expression,
7331 * and may also be of additional types not specified here.
7332 *
7333 * Early evaluation is possible since:
7334 * The variable bindings [...] used to evaluate a subexpression are
7335 * always the same as those used to evaluate the containing expression.
7336 *
7337 * [36] VariableReference ::= '$' QName
7338 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007339static void
7340xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007341 xmlChar *name;
7342 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007343
7344 SKIP_BLANKS;
7345 if (CUR != '$') {
7346 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7347 }
7348 NEXT;
7349 name = xmlXPathParseQName(ctxt, &prefix);
7350 if (name == NULL) {
7351 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7352 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007353 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007354 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7355 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007356 SKIP_BLANKS;
7357}
7358
7359/**
7360 * xmlXPathIsNodeType:
7361 * @ctxt: the XPath Parser context
7362 * @name: a name string
7363 *
7364 * Is the name given a NodeType one.
7365 *
7366 * [38] NodeType ::= 'comment'
7367 * | 'text'
7368 * | 'processing-instruction'
7369 * | 'node'
7370 *
7371 * Returns 1 if true 0 otherwise
7372 */
7373int
7374xmlXPathIsNodeType(const xmlChar *name) {
7375 if (name == NULL)
7376 return(0);
7377
Daniel Veillard1971ee22002-01-31 20:29:19 +00007378 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007379 return(1);
7380 if (xmlStrEqual(name, BAD_CAST "text"))
7381 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007382 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007383 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007384 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007385 return(1);
7386 return(0);
7387}
7388
7389/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007390 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007391 * @ctxt: the XPath Parser context
7392 *
7393 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7394 * [17] Argument ::= Expr
7395 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007396 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007397 * pushed on the stack
7398 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007399static void
7400xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007401 xmlChar *name;
7402 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007403 int nbargs = 0;
7404
7405 name = xmlXPathParseQName(ctxt, &prefix);
7406 if (name == NULL) {
7407 XP_ERROR(XPATH_EXPR_ERROR);
7408 }
7409 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007410#ifdef DEBUG_EXPR
7411 if (prefix == NULL)
7412 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7413 name);
7414 else
7415 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7416 prefix, name);
7417#endif
7418
Owen Taylor3473f882001-02-23 17:55:21 +00007419 if (CUR != '(') {
7420 XP_ERROR(XPATH_EXPR_ERROR);
7421 }
7422 NEXT;
7423 SKIP_BLANKS;
7424
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007425 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007426 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007427 int op1 = ctxt->comp->last;
7428 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007429 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007430 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007431 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007432 nbargs++;
7433 if (CUR == ')') break;
7434 if (CUR != ',') {
7435 XP_ERROR(XPATH_EXPR_ERROR);
7436 }
7437 NEXT;
7438 SKIP_BLANKS;
7439 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007440 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7441 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007442 NEXT;
7443 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007444}
7445
7446/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007447 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007448 * @ctxt: the XPath Parser context
7449 *
7450 * [15] PrimaryExpr ::= VariableReference
7451 * | '(' Expr ')'
7452 * | Literal
7453 * | Number
7454 * | FunctionCall
7455 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007456 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007457 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007458static void
7459xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007460 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007461 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007462 else if (CUR == '(') {
7463 NEXT;
7464 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007465 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007466 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00007467 if (CUR != ')') {
7468 XP_ERROR(XPATH_EXPR_ERROR);
7469 }
7470 NEXT;
7471 SKIP_BLANKS;
Daniel Veillard01917aa2002-04-10 11:30:41 +00007472 } else if (IS_DIGIT(CUR) || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007473 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007474 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007475 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007476 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007477 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007478 }
7479 SKIP_BLANKS;
7480}
7481
7482/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007483 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007484 * @ctxt: the XPath Parser context
7485 *
7486 * [20] FilterExpr ::= PrimaryExpr
7487 * | FilterExpr Predicate
7488 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007489 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007490 * Square brackets are used to filter expressions in the same way that
7491 * they are used in location paths. It is an error if the expression to
7492 * be filtered does not evaluate to a node-set. The context node list
7493 * used for evaluating the expression in square brackets is the node-set
7494 * to be filtered listed in document order.
7495 */
7496
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007497static void
7498xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
7499 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007500 CHECK_ERROR;
7501 SKIP_BLANKS;
7502
7503 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007504 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00007505 SKIP_BLANKS;
7506 }
7507
7508
7509}
7510
7511/**
7512 * xmlXPathScanName:
7513 * @ctxt: the XPath Parser context
7514 *
7515 * Trickery: parse an XML name but without consuming the input flow
7516 * Needed to avoid insanity in the parser state.
7517 *
7518 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7519 * CombiningChar | Extender
7520 *
7521 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7522 *
7523 * [6] Names ::= Name (S Name)*
7524 *
7525 * Returns the Name parsed or NULL
7526 */
7527
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007528static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007529xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7530 xmlChar buf[XML_MAX_NAMELEN];
7531 int len = 0;
7532
7533 SKIP_BLANKS;
7534 if (!IS_LETTER(CUR) && (CUR != '_') &&
7535 (CUR != ':')) {
7536 return(NULL);
7537 }
7538
7539 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7540 (NXT(len) == '.') || (NXT(len) == '-') ||
7541 (NXT(len) == '_') || (NXT(len) == ':') ||
7542 (IS_COMBINING(NXT(len))) ||
7543 (IS_EXTENDER(NXT(len)))) {
7544 buf[len] = NXT(len);
7545 len++;
7546 if (len >= XML_MAX_NAMELEN) {
7547 xmlGenericError(xmlGenericErrorContext,
7548 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
7549 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7550 (NXT(len) == '.') || (NXT(len) == '-') ||
7551 (NXT(len) == '_') || (NXT(len) == ':') ||
7552 (IS_COMBINING(NXT(len))) ||
7553 (IS_EXTENDER(NXT(len))))
7554 len++;
7555 break;
7556 }
7557 }
7558 return(xmlStrndup(buf, len));
7559}
7560
7561/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007562 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007563 * @ctxt: the XPath Parser context
7564 *
7565 * [19] PathExpr ::= LocationPath
7566 * | FilterExpr
7567 * | FilterExpr '/' RelativeLocationPath
7568 * | FilterExpr '//' RelativeLocationPath
7569 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007570 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007571 * The / operator and // operators combine an arbitrary expression
7572 * and a relative location path. It is an error if the expression
7573 * does not evaluate to a node-set.
7574 * The / operator does composition in the same way as when / is
7575 * used in a location path. As in location paths, // is short for
7576 * /descendant-or-self::node()/.
7577 */
7578
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007579static void
7580xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007581 int lc = 1; /* Should we branch to LocationPath ? */
7582 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7583
7584 SKIP_BLANKS;
7585 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
Daniel Veillard01917aa2002-04-10 11:30:41 +00007586 (CUR == '\'') || (CUR == '"') || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00007587 lc = 0;
7588 } else if (CUR == '*') {
7589 /* relative or absolute location path */
7590 lc = 1;
7591 } else if (CUR == '/') {
7592 /* relative or absolute location path */
7593 lc = 1;
7594 } else if (CUR == '@') {
7595 /* relative abbreviated attribute location path */
7596 lc = 1;
7597 } else if (CUR == '.') {
7598 /* relative abbreviated attribute location path */
7599 lc = 1;
7600 } else {
7601 /*
7602 * Problem is finding if we have a name here whether it's:
7603 * - a nodetype
7604 * - a function call in which case it's followed by '('
7605 * - an axis in which case it's followed by ':'
7606 * - a element name
7607 * We do an a priori analysis here rather than having to
7608 * maintain parsed token content through the recursive function
7609 * calls. This looks uglier but makes the code quite easier to
7610 * read/write/debug.
7611 */
7612 SKIP_BLANKS;
7613 name = xmlXPathScanName(ctxt);
7614 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7615#ifdef DEBUG_STEP
7616 xmlGenericError(xmlGenericErrorContext,
7617 "PathExpr: Axis\n");
7618#endif
7619 lc = 1;
7620 xmlFree(name);
7621 } else if (name != NULL) {
7622 int len =xmlStrlen(name);
7623 int blank = 0;
7624
7625
7626 while (NXT(len) != 0) {
7627 if (NXT(len) == '/') {
7628 /* element name */
7629#ifdef DEBUG_STEP
7630 xmlGenericError(xmlGenericErrorContext,
7631 "PathExpr: AbbrRelLocation\n");
7632#endif
7633 lc = 1;
7634 break;
7635 } else if (IS_BLANK(NXT(len))) {
7636 /* skip to next */
7637 blank = 1;
7638 } else if (NXT(len) == ':') {
7639#ifdef DEBUG_STEP
7640 xmlGenericError(xmlGenericErrorContext,
7641 "PathExpr: AbbrRelLocation\n");
7642#endif
7643 lc = 1;
7644 break;
7645 } else if ((NXT(len) == '(')) {
7646 /* Note Type or Function */
7647 if (xmlXPathIsNodeType(name)) {
7648#ifdef DEBUG_STEP
7649 xmlGenericError(xmlGenericErrorContext,
7650 "PathExpr: Type search\n");
7651#endif
7652 lc = 1;
7653 } else {
7654#ifdef DEBUG_STEP
7655 xmlGenericError(xmlGenericErrorContext,
7656 "PathExpr: function call\n");
7657#endif
7658 lc = 0;
7659 }
7660 break;
7661 } else if ((NXT(len) == '[')) {
7662 /* element name */
7663#ifdef DEBUG_STEP
7664 xmlGenericError(xmlGenericErrorContext,
7665 "PathExpr: AbbrRelLocation\n");
7666#endif
7667 lc = 1;
7668 break;
7669 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
7670 (NXT(len) == '=')) {
7671 lc = 1;
7672 break;
7673 } else {
7674 lc = 1;
7675 break;
7676 }
7677 len++;
7678 }
7679 if (NXT(len) == 0) {
7680#ifdef DEBUG_STEP
7681 xmlGenericError(xmlGenericErrorContext,
7682 "PathExpr: AbbrRelLocation\n");
7683#endif
7684 /* element name */
7685 lc = 1;
7686 }
7687 xmlFree(name);
7688 } else {
7689 /* make sure all cases are covered explicitely */
7690 XP_ERROR(XPATH_EXPR_ERROR);
7691 }
7692 }
7693
7694 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007695 if (CUR == '/') {
7696 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
7697 } else {
7698 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007699 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007700 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007701 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007702 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007703 CHECK_ERROR;
7704 if ((CUR == '/') && (NXT(1) == '/')) {
7705 SKIP(2);
7706 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007707
7708 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7709 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
7710 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
7711
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007712 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007713 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007714 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007715 }
7716 }
7717 SKIP_BLANKS;
7718}
7719
7720/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007721 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007722 * @ctxt: the XPath Parser context
7723 *
7724 * [18] UnionExpr ::= PathExpr
7725 * | UnionExpr '|' PathExpr
7726 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007727 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007728 */
7729
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007730static void
7731xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
7732 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007733 CHECK_ERROR;
7734 SKIP_BLANKS;
7735 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007736 int op1 = ctxt->comp->last;
7737 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007738
7739 NEXT;
7740 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007741 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007742
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007743 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
7744
Owen Taylor3473f882001-02-23 17:55:21 +00007745 SKIP_BLANKS;
7746 }
Owen Taylor3473f882001-02-23 17:55:21 +00007747}
7748
7749/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007750 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007751 * @ctxt: the XPath Parser context
7752 *
7753 * [27] UnaryExpr ::= UnionExpr
7754 * | '-' UnaryExpr
7755 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007756 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007757 */
7758
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007759static void
7760xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007761 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007762 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007763
7764 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00007765 while (CUR == '-') {
7766 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007767 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007768 NEXT;
7769 SKIP_BLANKS;
7770 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007771
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007772 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007773 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007774 if (found) {
7775 if (minus)
7776 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
7777 else
7778 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007779 }
7780}
7781
7782/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007783 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007784 * @ctxt: the XPath Parser context
7785 *
7786 * [26] MultiplicativeExpr ::= UnaryExpr
7787 * | MultiplicativeExpr MultiplyOperator UnaryExpr
7788 * | MultiplicativeExpr 'div' UnaryExpr
7789 * | MultiplicativeExpr 'mod' UnaryExpr
7790 * [34] MultiplyOperator ::= '*'
7791 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007792 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007793 */
7794
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007795static void
7796xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
7797 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007798 CHECK_ERROR;
7799 SKIP_BLANKS;
7800 while ((CUR == '*') ||
7801 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
7802 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
7803 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007804 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007805
7806 if (CUR == '*') {
7807 op = 0;
7808 NEXT;
7809 } else if (CUR == 'd') {
7810 op = 1;
7811 SKIP(3);
7812 } else if (CUR == 'm') {
7813 op = 2;
7814 SKIP(3);
7815 }
7816 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007817 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007818 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007819 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007820 SKIP_BLANKS;
7821 }
7822}
7823
7824/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007825 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007826 * @ctxt: the XPath Parser context
7827 *
7828 * [25] AdditiveExpr ::= MultiplicativeExpr
7829 * | AdditiveExpr '+' MultiplicativeExpr
7830 * | AdditiveExpr '-' MultiplicativeExpr
7831 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007832 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007833 */
7834
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007835static void
7836xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007837
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007838 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007839 CHECK_ERROR;
7840 SKIP_BLANKS;
7841 while ((CUR == '+') || (CUR == '-')) {
7842 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007843 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007844
7845 if (CUR == '+') plus = 1;
7846 else plus = 0;
7847 NEXT;
7848 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007849 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007850 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007851 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007852 SKIP_BLANKS;
7853 }
7854}
7855
7856/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007857 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007858 * @ctxt: the XPath Parser context
7859 *
7860 * [24] RelationalExpr ::= AdditiveExpr
7861 * | RelationalExpr '<' AdditiveExpr
7862 * | RelationalExpr '>' AdditiveExpr
7863 * | RelationalExpr '<=' AdditiveExpr
7864 * | RelationalExpr '>=' AdditiveExpr
7865 *
7866 * A <= B > C is allowed ? Answer from James, yes with
7867 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
7868 * which is basically what got implemented.
7869 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007870 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00007871 * on the stack
7872 */
7873
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007874static void
7875xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
7876 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007877 CHECK_ERROR;
7878 SKIP_BLANKS;
7879 while ((CUR == '<') ||
7880 (CUR == '>') ||
7881 ((CUR == '<') && (NXT(1) == '=')) ||
7882 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007883 int inf, strict;
7884 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007885
7886 if (CUR == '<') inf = 1;
7887 else inf = 0;
7888 if (NXT(1) == '=') strict = 0;
7889 else strict = 1;
7890 NEXT;
7891 if (!strict) NEXT;
7892 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007893 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007894 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007895 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00007896 SKIP_BLANKS;
7897 }
7898}
7899
7900/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007901 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007902 * @ctxt: the XPath Parser context
7903 *
7904 * [23] EqualityExpr ::= RelationalExpr
7905 * | EqualityExpr '=' RelationalExpr
7906 * | EqualityExpr '!=' RelationalExpr
7907 *
7908 * A != B != C is allowed ? Answer from James, yes with
7909 * (RelationalExpr = RelationalExpr) = RelationalExpr
7910 * (RelationalExpr != RelationalExpr) != RelationalExpr
7911 * which is basically what got implemented.
7912 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007913 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007914 *
7915 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007916static void
7917xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
7918 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007919 CHECK_ERROR;
7920 SKIP_BLANKS;
7921 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007922 int eq;
7923 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007924
7925 if (CUR == '=') eq = 1;
7926 else eq = 0;
7927 NEXT;
7928 if (!eq) NEXT;
7929 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007930 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007931 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007932 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007933 SKIP_BLANKS;
7934 }
7935}
7936
7937/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007938 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007939 * @ctxt: the XPath Parser context
7940 *
7941 * [22] AndExpr ::= EqualityExpr
7942 * | AndExpr 'and' EqualityExpr
7943 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007944 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007945 *
7946 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007947static void
7948xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
7949 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007950 CHECK_ERROR;
7951 SKIP_BLANKS;
7952 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007953 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007954 SKIP(3);
7955 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007956 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007957 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007958 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007959 SKIP_BLANKS;
7960 }
7961}
7962
7963/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007964 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007965 * @ctxt: the XPath Parser context
7966 *
7967 * [14] Expr ::= OrExpr
7968 * [21] OrExpr ::= AndExpr
7969 * | OrExpr 'or' AndExpr
7970 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007971 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00007972 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007973static void
7974xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
7975 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007976 CHECK_ERROR;
7977 SKIP_BLANKS;
7978 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007979 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007980 SKIP(2);
7981 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007982 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007983 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007984 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
7985 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00007986 SKIP_BLANKS;
7987 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007988 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
7989 /* more ops could be optimized too */
7990 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
7991 }
Owen Taylor3473f882001-02-23 17:55:21 +00007992}
7993
7994/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007995 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00007996 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007997 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00007998 *
7999 * [8] Predicate ::= '[' PredicateExpr ']'
8000 * [9] PredicateExpr ::= Expr
8001 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008002 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008003 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008004static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008005xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008006 int op1 = ctxt->comp->last;
8007
8008 SKIP_BLANKS;
8009 if (CUR != '[') {
8010 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8011 }
8012 NEXT;
8013 SKIP_BLANKS;
8014
8015 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008016 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008017 CHECK_ERROR;
8018
8019 if (CUR != ']') {
8020 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8021 }
8022
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008023 if (filter)
8024 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8025 else
8026 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008027
8028 NEXT;
8029 SKIP_BLANKS;
8030}
8031
8032/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008033 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00008034 * @ctxt: the XPath Parser context
8035 * @test: pointer to a xmlXPathTestVal
8036 * @type: pointer to a xmlXPathTypeVal
8037 * @prefix: placeholder for a possible name prefix
8038 *
8039 * [7] NodeTest ::= NameTest
8040 * | NodeType '(' ')'
8041 * | 'processing-instruction' '(' Literal ')'
8042 *
8043 * [37] NameTest ::= '*'
8044 * | NCName ':' '*'
8045 * | QName
8046 * [38] NodeType ::= 'comment'
8047 * | 'text'
8048 * | 'processing-instruction'
8049 * | 'node'
8050 *
8051 * Returns the name found and update @test, @type and @prefix appropriately
8052 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008053static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008054xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8055 xmlXPathTypeVal *type, const xmlChar **prefix,
8056 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008057 int blanks;
8058
8059 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8060 STRANGE;
8061 return(NULL);
8062 }
8063 *type = 0;
8064 *test = 0;
8065 *prefix = NULL;
8066 SKIP_BLANKS;
8067
8068 if ((name == NULL) && (CUR == '*')) {
8069 /*
8070 * All elements
8071 */
8072 NEXT;
8073 *test = NODE_TEST_ALL;
8074 return(NULL);
8075 }
8076
8077 if (name == NULL)
8078 name = xmlXPathParseNCName(ctxt);
8079 if (name == NULL) {
8080 XP_ERROR0(XPATH_EXPR_ERROR);
8081 }
8082
8083 blanks = IS_BLANK(CUR);
8084 SKIP_BLANKS;
8085 if (CUR == '(') {
8086 NEXT;
8087 /*
8088 * NodeType or PI search
8089 */
8090 if (xmlStrEqual(name, BAD_CAST "comment"))
8091 *type = NODE_TYPE_COMMENT;
8092 else if (xmlStrEqual(name, BAD_CAST "node"))
8093 *type = NODE_TYPE_NODE;
8094 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8095 *type = NODE_TYPE_PI;
8096 else if (xmlStrEqual(name, BAD_CAST "text"))
8097 *type = NODE_TYPE_TEXT;
8098 else {
8099 if (name != NULL)
8100 xmlFree(name);
8101 XP_ERROR0(XPATH_EXPR_ERROR);
8102 }
8103
8104 *test = NODE_TEST_TYPE;
8105
8106 SKIP_BLANKS;
8107 if (*type == NODE_TYPE_PI) {
8108 /*
8109 * Specific case: search a PI by name.
8110 */
Owen Taylor3473f882001-02-23 17:55:21 +00008111 if (name != NULL)
8112 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008113 name = NULL;
8114 if (CUR != ')') {
8115 name = xmlXPathParseLiteral(ctxt);
8116 CHECK_ERROR 0;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00008117 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00008118 SKIP_BLANKS;
8119 }
Owen Taylor3473f882001-02-23 17:55:21 +00008120 }
8121 if (CUR != ')') {
8122 if (name != NULL)
8123 xmlFree(name);
8124 XP_ERROR0(XPATH_UNCLOSED_ERROR);
8125 }
8126 NEXT;
8127 return(name);
8128 }
8129 *test = NODE_TEST_NAME;
8130 if ((!blanks) && (CUR == ':')) {
8131 NEXT;
8132
8133 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008134 * Since currently the parser context don't have a
8135 * namespace list associated:
8136 * The namespace name for this prefix can be computed
8137 * only at evaluation time. The compilation is done
8138 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008139 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008140#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008141 *prefix = xmlXPathNsLookup(ctxt->context, name);
8142 if (name != NULL)
8143 xmlFree(name);
8144 if (*prefix == NULL) {
8145 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8146 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008147#else
8148 *prefix = name;
8149#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008150
8151 if (CUR == '*') {
8152 /*
8153 * All elements
8154 */
8155 NEXT;
8156 *test = NODE_TEST_ALL;
8157 return(NULL);
8158 }
8159
8160 name = xmlXPathParseNCName(ctxt);
8161 if (name == NULL) {
8162 XP_ERROR0(XPATH_EXPR_ERROR);
8163 }
8164 }
8165 return(name);
8166}
8167
8168/**
8169 * xmlXPathIsAxisName:
8170 * @name: a preparsed name token
8171 *
8172 * [6] AxisName ::= 'ancestor'
8173 * | 'ancestor-or-self'
8174 * | 'attribute'
8175 * | 'child'
8176 * | 'descendant'
8177 * | 'descendant-or-self'
8178 * | 'following'
8179 * | 'following-sibling'
8180 * | 'namespace'
8181 * | 'parent'
8182 * | 'preceding'
8183 * | 'preceding-sibling'
8184 * | 'self'
8185 *
8186 * Returns the axis or 0
8187 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008188static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008189xmlXPathIsAxisName(const xmlChar *name) {
8190 xmlXPathAxisVal ret = 0;
8191 switch (name[0]) {
8192 case 'a':
8193 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8194 ret = AXIS_ANCESTOR;
8195 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8196 ret = AXIS_ANCESTOR_OR_SELF;
8197 if (xmlStrEqual(name, BAD_CAST "attribute"))
8198 ret = AXIS_ATTRIBUTE;
8199 break;
8200 case 'c':
8201 if (xmlStrEqual(name, BAD_CAST "child"))
8202 ret = AXIS_CHILD;
8203 break;
8204 case 'd':
8205 if (xmlStrEqual(name, BAD_CAST "descendant"))
8206 ret = AXIS_DESCENDANT;
8207 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8208 ret = AXIS_DESCENDANT_OR_SELF;
8209 break;
8210 case 'f':
8211 if (xmlStrEqual(name, BAD_CAST "following"))
8212 ret = AXIS_FOLLOWING;
8213 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8214 ret = AXIS_FOLLOWING_SIBLING;
8215 break;
8216 case 'n':
8217 if (xmlStrEqual(name, BAD_CAST "namespace"))
8218 ret = AXIS_NAMESPACE;
8219 break;
8220 case 'p':
8221 if (xmlStrEqual(name, BAD_CAST "parent"))
8222 ret = AXIS_PARENT;
8223 if (xmlStrEqual(name, BAD_CAST "preceding"))
8224 ret = AXIS_PRECEDING;
8225 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8226 ret = AXIS_PRECEDING_SIBLING;
8227 break;
8228 case 's':
8229 if (xmlStrEqual(name, BAD_CAST "self"))
8230 ret = AXIS_SELF;
8231 break;
8232 }
8233 return(ret);
8234}
8235
8236/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008237 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008238 * @ctxt: the XPath Parser context
8239 *
8240 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8241 * | AbbreviatedStep
8242 *
8243 * [12] AbbreviatedStep ::= '.' | '..'
8244 *
8245 * [5] AxisSpecifier ::= AxisName '::'
8246 * | AbbreviatedAxisSpecifier
8247 *
8248 * [13] AbbreviatedAxisSpecifier ::= '@'?
8249 *
8250 * Modified for XPtr range support as:
8251 *
8252 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8253 * | AbbreviatedStep
8254 * | 'range-to' '(' Expr ')' Predicate*
8255 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008256 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008257 * A location step of . is short for self::node(). This is
8258 * particularly useful in conjunction with //. For example, the
8259 * location path .//para is short for
8260 * self::node()/descendant-or-self::node()/child::para
8261 * and so will select all para descendant elements of the context
8262 * node.
8263 * Similarly, a location step of .. is short for parent::node().
8264 * For example, ../title is short for parent::node()/child::title
8265 * and so will select the title children of the parent of the context
8266 * node.
8267 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008268static void
8269xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008270#ifdef LIBXML_XPTR_ENABLED
8271 int rangeto = 0;
8272 int op2 = -1;
8273#endif
8274
Owen Taylor3473f882001-02-23 17:55:21 +00008275 SKIP_BLANKS;
8276 if ((CUR == '.') && (NXT(1) == '.')) {
8277 SKIP(2);
8278 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008279 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8280 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008281 } else if (CUR == '.') {
8282 NEXT;
8283 SKIP_BLANKS;
8284 } else {
8285 xmlChar *name = NULL;
8286 const xmlChar *prefix = NULL;
8287 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008288 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008289 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008290 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008291
8292 /*
8293 * The modification needed for XPointer change to the production
8294 */
8295#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008296 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008297 name = xmlXPathParseNCName(ctxt);
8298 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008299 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008300 xmlFree(name);
8301 SKIP_BLANKS;
8302 if (CUR != '(') {
8303 XP_ERROR(XPATH_EXPR_ERROR);
8304 }
8305 NEXT;
8306 SKIP_BLANKS;
8307
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008308 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008309 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008310 CHECK_ERROR;
8311
8312 SKIP_BLANKS;
8313 if (CUR != ')') {
8314 XP_ERROR(XPATH_EXPR_ERROR);
8315 }
8316 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008317 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008318 goto eval_predicates;
8319 }
8320 }
8321#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008322 if (CUR == '*') {
8323 axis = AXIS_CHILD;
8324 } else {
8325 if (name == NULL)
8326 name = xmlXPathParseNCName(ctxt);
8327 if (name != NULL) {
8328 axis = xmlXPathIsAxisName(name);
8329 if (axis != 0) {
8330 SKIP_BLANKS;
8331 if ((CUR == ':') && (NXT(1) == ':')) {
8332 SKIP(2);
8333 xmlFree(name);
8334 name = NULL;
8335 } else {
8336 /* an element name can conflict with an axis one :-\ */
8337 axis = AXIS_CHILD;
8338 }
Owen Taylor3473f882001-02-23 17:55:21 +00008339 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008340 axis = AXIS_CHILD;
8341 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008342 } else if (CUR == '@') {
8343 NEXT;
8344 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008345 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008346 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008347 }
Owen Taylor3473f882001-02-23 17:55:21 +00008348 }
8349
8350 CHECK_ERROR;
8351
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008352 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008353 if (test == 0)
8354 return;
8355
8356#ifdef DEBUG_STEP
8357 xmlGenericError(xmlGenericErrorContext,
8358 "Basis : computing new set\n");
8359#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008360
Owen Taylor3473f882001-02-23 17:55:21 +00008361#ifdef DEBUG_STEP
8362 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008363 if (ctxt->value == NULL)
8364 xmlGenericError(xmlGenericErrorContext, "no value\n");
8365 else if (ctxt->value->nodesetval == NULL)
8366 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8367 else
8368 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008369#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008370
8371eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008372 op1 = ctxt->comp->last;
8373 ctxt->comp->last = -1;
8374
Owen Taylor3473f882001-02-23 17:55:21 +00008375 SKIP_BLANKS;
8376 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008377 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008378 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008379
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008380#ifdef LIBXML_XPTR_ENABLED
8381 if (rangeto) {
8382 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8383 } else
8384#endif
8385 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8386 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008387
Owen Taylor3473f882001-02-23 17:55:21 +00008388 }
8389#ifdef DEBUG_STEP
8390 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008391 if (ctxt->value == NULL)
8392 xmlGenericError(xmlGenericErrorContext, "no value\n");
8393 else if (ctxt->value->nodesetval == NULL)
8394 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8395 else
8396 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8397 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008398#endif
8399}
8400
8401/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008402 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008403 * @ctxt: the XPath Parser context
8404 *
8405 * [3] RelativeLocationPath ::= Step
8406 * | RelativeLocationPath '/' Step
8407 * | AbbreviatedRelativeLocationPath
8408 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8409 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008410 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008411 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008412static void
Owen Taylor3473f882001-02-23 17:55:21 +00008413#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008414xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008415#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008416xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008417#endif
8418(xmlXPathParserContextPtr ctxt) {
8419 SKIP_BLANKS;
8420 if ((CUR == '/') && (NXT(1) == '/')) {
8421 SKIP(2);
8422 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008423 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8424 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008425 } else if (CUR == '/') {
8426 NEXT;
8427 SKIP_BLANKS;
8428 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008429 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008430 SKIP_BLANKS;
8431 while (CUR == '/') {
8432 if ((CUR == '/') && (NXT(1) == '/')) {
8433 SKIP(2);
8434 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008435 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008436 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008437 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008438 } else if (CUR == '/') {
8439 NEXT;
8440 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008441 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008442 }
8443 SKIP_BLANKS;
8444 }
8445}
8446
8447/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008448 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008449 * @ctxt: the XPath Parser context
8450 *
8451 * [1] LocationPath ::= RelativeLocationPath
8452 * | AbsoluteLocationPath
8453 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8454 * | AbbreviatedAbsoluteLocationPath
8455 * [10] AbbreviatedAbsoluteLocationPath ::=
8456 * '//' RelativeLocationPath
8457 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008458 * Compile a location path
8459 *
Owen Taylor3473f882001-02-23 17:55:21 +00008460 * // is short for /descendant-or-self::node()/. For example,
8461 * //para is short for /descendant-or-self::node()/child::para and
8462 * so will select any para element in the document (even a para element
8463 * that is a document element will be selected by //para since the
8464 * document element node is a child of the root node); div//para is
8465 * short for div/descendant-or-self::node()/child::para and so will
8466 * select all para descendants of div children.
8467 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008468static void
8469xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008470 SKIP_BLANKS;
8471 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008472 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008473 } else {
8474 while (CUR == '/') {
8475 if ((CUR == '/') && (NXT(1) == '/')) {
8476 SKIP(2);
8477 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008478 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8479 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008480 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008481 } else if (CUR == '/') {
8482 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008483 SKIP_BLANKS;
8484 if ((CUR != 0 ) &&
8485 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
8486 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008487 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008488 }
8489 }
8490 }
8491}
8492
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008493/************************************************************************
8494 * *
8495 * XPath precompiled expression evaluation *
8496 * *
8497 ************************************************************************/
8498
Daniel Veillardf06307e2001-07-03 10:35:50 +00008499static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008500xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8501
8502/**
8503 * xmlXPathNodeCollectAndTest:
8504 * @ctxt: the XPath Parser context
8505 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008506 * @first: pointer to the first element in document order
8507 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008508 *
8509 * This is the function implementing a step: based on the current list
8510 * of nodes, it builds up a new list, looking at all nodes under that
8511 * axis and selecting them it also do the predicate filtering
8512 *
8513 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00008514 *
8515 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008516 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008517static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008518xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008519 xmlXPathStepOpPtr op,
8520 xmlNodePtr * first, xmlNodePtr * last)
8521{
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008522 xmlXPathAxisVal axis = op->value;
8523 xmlXPathTestVal test = op->value2;
8524 xmlXPathTypeVal type = op->value3;
8525 const xmlChar *prefix = op->value4;
8526 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008527 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008528
8529#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008530 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008531#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008532 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008533 xmlNodeSetPtr ret, list;
8534 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008535 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00008536 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008537 xmlNodePtr cur = NULL;
8538 xmlXPathObjectPtr obj;
8539 xmlNodeSetPtr nodelist;
8540 xmlNodePtr tmp;
8541
Daniel Veillardf06307e2001-07-03 10:35:50 +00008542 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008543 obj = valuePop(ctxt);
8544 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00008545 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008546 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008547 URI = xmlXPathNsLookup(ctxt->context, prefix);
8548 if (URI == NULL)
8549 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008550 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008551#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008552 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008553#endif
8554 switch (axis) {
8555 case AXIS_ANCESTOR:
8556#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008557 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008558#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008559 first = NULL;
8560 next = xmlXPathNextAncestor;
8561 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008562 case AXIS_ANCESTOR_OR_SELF:
8563#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008564 xmlGenericError(xmlGenericErrorContext,
8565 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008566#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008567 first = NULL;
8568 next = xmlXPathNextAncestorOrSelf;
8569 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008570 case AXIS_ATTRIBUTE:
8571#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008572 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008573#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008574 first = NULL;
8575 last = NULL;
8576 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00008577 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008578 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008579 case AXIS_CHILD:
8580#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008581 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008582#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008583 last = NULL;
8584 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00008585 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008586 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008587 case AXIS_DESCENDANT:
8588#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008589 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008590#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008591 last = NULL;
8592 next = xmlXPathNextDescendant;
8593 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008594 case AXIS_DESCENDANT_OR_SELF:
8595#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008596 xmlGenericError(xmlGenericErrorContext,
8597 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008598#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008599 last = NULL;
8600 next = xmlXPathNextDescendantOrSelf;
8601 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008602 case AXIS_FOLLOWING:
8603#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008604 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008605#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008606 last = NULL;
8607 next = xmlXPathNextFollowing;
8608 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008609 case AXIS_FOLLOWING_SIBLING:
8610#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008611 xmlGenericError(xmlGenericErrorContext,
8612 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008613#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008614 last = NULL;
8615 next = xmlXPathNextFollowingSibling;
8616 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008617 case AXIS_NAMESPACE:
8618#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008619 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008620#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008621 first = NULL;
8622 last = NULL;
8623 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00008624 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008625 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008626 case AXIS_PARENT:
8627#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008628 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008629#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008630 first = NULL;
8631 next = xmlXPathNextParent;
8632 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008633 case AXIS_PRECEDING:
8634#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008635 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008636#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008637 first = NULL;
8638 next = xmlXPathNextPrecedingInternal;
8639 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008640 case AXIS_PRECEDING_SIBLING:
8641#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008642 xmlGenericError(xmlGenericErrorContext,
8643 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008644#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008645 first = NULL;
8646 next = xmlXPathNextPrecedingSibling;
8647 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008648 case AXIS_SELF:
8649#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008650 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008651#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008652 first = NULL;
8653 last = NULL;
8654 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00008655 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008656 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008657 }
8658 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008659 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008660
8661 nodelist = obj->nodesetval;
8662 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008663 xmlXPathFreeObject(obj);
8664 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8665 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008666 }
8667 addNode = xmlXPathNodeSetAddUnique;
8668 ret = NULL;
8669#ifdef DEBUG_STEP
8670 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008671 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008672 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008673 case NODE_TEST_NONE:
8674 xmlGenericError(xmlGenericErrorContext,
8675 " searching for none !!!\n");
8676 break;
8677 case NODE_TEST_TYPE:
8678 xmlGenericError(xmlGenericErrorContext,
8679 " searching for type %d\n", type);
8680 break;
8681 case NODE_TEST_PI:
8682 xmlGenericError(xmlGenericErrorContext,
8683 " searching for PI !!!\n");
8684 break;
8685 case NODE_TEST_ALL:
8686 xmlGenericError(xmlGenericErrorContext,
8687 " searching for *\n");
8688 break;
8689 case NODE_TEST_NS:
8690 xmlGenericError(xmlGenericErrorContext,
8691 " searching for namespace %s\n",
8692 prefix);
8693 break;
8694 case NODE_TEST_NAME:
8695 xmlGenericError(xmlGenericErrorContext,
8696 " searching for name %s\n", name);
8697 if (prefix != NULL)
8698 xmlGenericError(xmlGenericErrorContext,
8699 " with namespace %s\n", prefix);
8700 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008701 }
8702 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8703#endif
8704 /*
8705 * 2.3 Node Tests
8706 * - For the attribute axis, the principal node type is attribute.
8707 * - For the namespace axis, the principal node type is namespace.
8708 * - For other axes, the principal node type is element.
8709 *
8710 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008711 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008712 * select all element children of the context node
8713 */
8714 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008715 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008716 ctxt->context->node = nodelist->nodeTab[i];
8717
Daniel Veillardf06307e2001-07-03 10:35:50 +00008718 cur = NULL;
8719 list = xmlXPathNodeSetCreate(NULL);
8720 do {
8721 cur = next(ctxt, cur);
8722 if (cur == NULL)
8723 break;
8724 if ((first != NULL) && (*first == cur))
8725 break;
8726 if (((t % 256) == 0) &&
8727 (first != NULL) && (*first != NULL) &&
8728 (xmlXPathCmpNodes(*first, cur) >= 0))
8729 break;
8730 if ((last != NULL) && (*last == cur))
8731 break;
8732 if (((t % 256) == 0) &&
8733 (last != NULL) && (*last != NULL) &&
8734 (xmlXPathCmpNodes(cur, *last) >= 0))
8735 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008736 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008737#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008738 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
8739#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008740 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008741 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008742 ctxt->context->node = tmp;
8743 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008744 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008745 if ((cur->type == type) ||
8746 ((type == NODE_TYPE_NODE) &&
8747 ((cur->type == XML_DOCUMENT_NODE) ||
8748 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8749 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00008750 (cur->type == XML_NAMESPACE_DECL) ||
8751 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00008752 (cur->type == XML_PI_NODE) ||
8753 (cur->type == XML_COMMENT_NODE) ||
8754 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00008755 (cur->type == XML_TEXT_NODE))) ||
8756 ((type == NODE_TYPE_TEXT) &&
8757 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008758#ifdef DEBUG_STEP
8759 n++;
8760#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008761 addNode(list, cur);
8762 }
8763 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008764 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008765 if (cur->type == XML_PI_NODE) {
8766 if ((name != NULL) &&
8767 (!xmlStrEqual(name, cur->name)))
8768 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008769#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008770 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008771#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008772 addNode(list, cur);
8773 }
8774 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008775 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008776 if (axis == AXIS_ATTRIBUTE) {
8777 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008778#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008779 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008780#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008781 addNode(list, cur);
8782 }
8783 } else if (axis == AXIS_NAMESPACE) {
8784 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008785#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008786 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008787#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008788 xmlXPathNodeSetAddNs(list, ctxt->context->node,
8789 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008790 }
8791 } else {
8792 if (cur->type == XML_ELEMENT_NODE) {
8793 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008794#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008795 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008796#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008797 addNode(list, cur);
8798 } else if ((cur->ns != NULL) &&
8799 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008800#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008801 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008802#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008803 addNode(list, cur);
8804 }
8805 }
8806 }
8807 break;
8808 case NODE_TEST_NS:{
8809 TODO;
8810 break;
8811 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008812 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008813 switch (cur->type) {
8814 case XML_ELEMENT_NODE:
8815 if (xmlStrEqual(name, cur->name)) {
8816 if (prefix == NULL) {
8817 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008818#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008819 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008820#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008821 addNode(list, cur);
8822 }
8823 } else {
8824 if ((cur->ns != NULL) &&
8825 (xmlStrEqual(URI,
8826 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008827#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008828 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008829#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008830 addNode(list, cur);
8831 }
8832 }
8833 }
8834 break;
8835 case XML_ATTRIBUTE_NODE:{
8836 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008837
Daniel Veillardf06307e2001-07-03 10:35:50 +00008838 if (xmlStrEqual(name, attr->name)) {
8839 if (prefix == NULL) {
8840 if ((attr->ns == NULL) ||
8841 (attr->ns->prefix == NULL)) {
8842#ifdef DEBUG_STEP
8843 n++;
8844#endif
8845 addNode(list,
8846 (xmlNodePtr) attr);
8847 }
8848 } else {
8849 if ((attr->ns != NULL) &&
8850 (xmlStrEqual(URI,
8851 attr->ns->
8852 href))) {
8853#ifdef DEBUG_STEP
8854 n++;
8855#endif
8856 addNode(list,
8857 (xmlNodePtr) attr);
8858 }
8859 }
8860 }
8861 break;
8862 }
8863 case XML_NAMESPACE_DECL:
8864 if (cur->type == XML_NAMESPACE_DECL) {
8865 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008866
Daniel Veillardf06307e2001-07-03 10:35:50 +00008867 if ((ns->prefix != NULL) && (name != NULL)
8868 && (xmlStrEqual(ns->prefix, name))) {
8869#ifdef DEBUG_STEP
8870 n++;
8871#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008872 xmlXPathNodeSetAddNs(list,
8873 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008874 }
8875 }
8876 break;
8877 default:
8878 break;
8879 }
8880 break;
8881 break;
8882 }
8883 } while (cur != NULL);
8884
8885 /*
8886 * If there is some predicate filtering do it now
8887 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00008888 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008889 xmlXPathObjectPtr obj2;
8890
8891 valuePush(ctxt, xmlXPathWrapNodeSet(list));
8892 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
8893 CHECK_TYPE0(XPATH_NODESET);
8894 obj2 = valuePop(ctxt);
8895 list = obj2->nodesetval;
8896 obj2->nodesetval = NULL;
8897 xmlXPathFreeObject(obj2);
8898 }
8899 if (ret == NULL) {
8900 ret = list;
8901 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00008902 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008903 xmlXPathFreeNodeSet(list);
8904 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008905 }
8906 ctxt->context->node = tmp;
8907#ifdef DEBUG_STEP
8908 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008909 "\nExamined %d nodes, found %d nodes at that step\n",
8910 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008911#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008912 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00008913 if ((obj->boolval) && (obj->user != NULL)) {
8914 ctxt->value->boolval = 1;
8915 ctxt->value->user = obj->user;
8916 obj->user = NULL;
8917 obj->boolval = 0;
8918 }
8919 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008920 return(t);
8921}
8922
8923/**
8924 * xmlXPathNodeCollectAndTestNth:
8925 * @ctxt: the XPath Parser context
8926 * @op: the XPath precompiled step operation
8927 * @indx: the index to collect
8928 * @first: pointer to the first element in document order
8929 * @last: pointer to the last element in document order
8930 *
8931 * This is the function implementing a step: based on the current list
8932 * of nodes, it builds up a new list, looking at all nodes under that
8933 * axis and selecting them it also do the predicate filtering
8934 *
8935 * Pushes the new NodeSet resulting from the search.
8936 * Returns the number of node traversed
8937 */
8938static int
8939xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
8940 xmlXPathStepOpPtr op, int indx,
8941 xmlNodePtr * first, xmlNodePtr * last)
8942{
8943 xmlXPathAxisVal axis = op->value;
8944 xmlXPathTestVal test = op->value2;
8945 xmlXPathTypeVal type = op->value3;
8946 const xmlChar *prefix = op->value4;
8947 const xmlChar *name = op->value5;
8948 const xmlChar *URI = NULL;
8949 int n = 0, t = 0;
8950
8951 int i;
8952 xmlNodeSetPtr list;
8953 xmlXPathTraversalFunction next = NULL;
8954 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
8955 xmlNodePtr cur = NULL;
8956 xmlXPathObjectPtr obj;
8957 xmlNodeSetPtr nodelist;
8958 xmlNodePtr tmp;
8959
8960 CHECK_TYPE0(XPATH_NODESET);
8961 obj = valuePop(ctxt);
8962 addNode = xmlXPathNodeSetAdd;
8963 if (prefix != NULL) {
8964 URI = xmlXPathNsLookup(ctxt->context, prefix);
8965 if (URI == NULL)
8966 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8967 }
8968#ifdef DEBUG_STEP_NTH
8969 xmlGenericError(xmlGenericErrorContext, "new step : ");
8970 if (first != NULL) {
8971 if (*first != NULL)
8972 xmlGenericError(xmlGenericErrorContext, "first = %s ",
8973 (*first)->name);
8974 else
8975 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
8976 }
8977 if (last != NULL) {
8978 if (*last != NULL)
8979 xmlGenericError(xmlGenericErrorContext, "last = %s ",
8980 (*last)->name);
8981 else
8982 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
8983 }
8984#endif
8985 switch (axis) {
8986 case AXIS_ANCESTOR:
8987#ifdef DEBUG_STEP_NTH
8988 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
8989#endif
8990 first = NULL;
8991 next = xmlXPathNextAncestor;
8992 break;
8993 case AXIS_ANCESTOR_OR_SELF:
8994#ifdef DEBUG_STEP_NTH
8995 xmlGenericError(xmlGenericErrorContext,
8996 "axis 'ancestors-or-self' ");
8997#endif
8998 first = NULL;
8999 next = xmlXPathNextAncestorOrSelf;
9000 break;
9001 case AXIS_ATTRIBUTE:
9002#ifdef DEBUG_STEP_NTH
9003 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9004#endif
9005 first = NULL;
9006 last = NULL;
9007 next = xmlXPathNextAttribute;
9008 break;
9009 case AXIS_CHILD:
9010#ifdef DEBUG_STEP_NTH
9011 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9012#endif
9013 last = NULL;
9014 next = xmlXPathNextChild;
9015 break;
9016 case AXIS_DESCENDANT:
9017#ifdef DEBUG_STEP_NTH
9018 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9019#endif
9020 last = NULL;
9021 next = xmlXPathNextDescendant;
9022 break;
9023 case AXIS_DESCENDANT_OR_SELF:
9024#ifdef DEBUG_STEP_NTH
9025 xmlGenericError(xmlGenericErrorContext,
9026 "axis 'descendant-or-self' ");
9027#endif
9028 last = NULL;
9029 next = xmlXPathNextDescendantOrSelf;
9030 break;
9031 case AXIS_FOLLOWING:
9032#ifdef DEBUG_STEP_NTH
9033 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9034#endif
9035 last = NULL;
9036 next = xmlXPathNextFollowing;
9037 break;
9038 case AXIS_FOLLOWING_SIBLING:
9039#ifdef DEBUG_STEP_NTH
9040 xmlGenericError(xmlGenericErrorContext,
9041 "axis 'following-siblings' ");
9042#endif
9043 last = NULL;
9044 next = xmlXPathNextFollowingSibling;
9045 break;
9046 case AXIS_NAMESPACE:
9047#ifdef DEBUG_STEP_NTH
9048 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9049#endif
9050 last = NULL;
9051 first = NULL;
9052 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9053 break;
9054 case AXIS_PARENT:
9055#ifdef DEBUG_STEP_NTH
9056 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9057#endif
9058 first = NULL;
9059 next = xmlXPathNextParent;
9060 break;
9061 case AXIS_PRECEDING:
9062#ifdef DEBUG_STEP_NTH
9063 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9064#endif
9065 first = NULL;
9066 next = xmlXPathNextPrecedingInternal;
9067 break;
9068 case AXIS_PRECEDING_SIBLING:
9069#ifdef DEBUG_STEP_NTH
9070 xmlGenericError(xmlGenericErrorContext,
9071 "axis 'preceding-sibling' ");
9072#endif
9073 first = NULL;
9074 next = xmlXPathNextPrecedingSibling;
9075 break;
9076 case AXIS_SELF:
9077#ifdef DEBUG_STEP_NTH
9078 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9079#endif
9080 first = NULL;
9081 last = NULL;
9082 next = xmlXPathNextSelf;
9083 break;
9084 }
9085 if (next == NULL)
9086 return(0);
9087
9088 nodelist = obj->nodesetval;
9089 if (nodelist == NULL) {
9090 xmlXPathFreeObject(obj);
9091 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9092 return(0);
9093 }
9094 addNode = xmlXPathNodeSetAddUnique;
9095#ifdef DEBUG_STEP_NTH
9096 xmlGenericError(xmlGenericErrorContext,
9097 " context contains %d nodes\n", nodelist->nodeNr);
9098 switch (test) {
9099 case NODE_TEST_NONE:
9100 xmlGenericError(xmlGenericErrorContext,
9101 " searching for none !!!\n");
9102 break;
9103 case NODE_TEST_TYPE:
9104 xmlGenericError(xmlGenericErrorContext,
9105 " searching for type %d\n", type);
9106 break;
9107 case NODE_TEST_PI:
9108 xmlGenericError(xmlGenericErrorContext,
9109 " searching for PI !!!\n");
9110 break;
9111 case NODE_TEST_ALL:
9112 xmlGenericError(xmlGenericErrorContext,
9113 " searching for *\n");
9114 break;
9115 case NODE_TEST_NS:
9116 xmlGenericError(xmlGenericErrorContext,
9117 " searching for namespace %s\n",
9118 prefix);
9119 break;
9120 case NODE_TEST_NAME:
9121 xmlGenericError(xmlGenericErrorContext,
9122 " searching for name %s\n", name);
9123 if (prefix != NULL)
9124 xmlGenericError(xmlGenericErrorContext,
9125 " with namespace %s\n", prefix);
9126 break;
9127 }
9128 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9129#endif
9130 /*
9131 * 2.3 Node Tests
9132 * - For the attribute axis, the principal node type is attribute.
9133 * - For the namespace axis, the principal node type is namespace.
9134 * - For other axes, the principal node type is element.
9135 *
9136 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009137 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009138 * select all element children of the context node
9139 */
9140 tmp = ctxt->context->node;
9141 list = xmlXPathNodeSetCreate(NULL);
9142 for (i = 0; i < nodelist->nodeNr; i++) {
9143 ctxt->context->node = nodelist->nodeTab[i];
9144
9145 cur = NULL;
9146 n = 0;
9147 do {
9148 cur = next(ctxt, cur);
9149 if (cur == NULL)
9150 break;
9151 if ((first != NULL) && (*first == cur))
9152 break;
9153 if (((t % 256) == 0) &&
9154 (first != NULL) && (*first != NULL) &&
9155 (xmlXPathCmpNodes(*first, cur) >= 0))
9156 break;
9157 if ((last != NULL) && (*last == cur))
9158 break;
9159 if (((t % 256) == 0) &&
9160 (last != NULL) && (*last != NULL) &&
9161 (xmlXPathCmpNodes(cur, *last) >= 0))
9162 break;
9163 t++;
9164 switch (test) {
9165 case NODE_TEST_NONE:
9166 ctxt->context->node = tmp;
9167 STRANGE return(0);
9168 case NODE_TEST_TYPE:
9169 if ((cur->type == type) ||
9170 ((type == NODE_TYPE_NODE) &&
9171 ((cur->type == XML_DOCUMENT_NODE) ||
9172 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9173 (cur->type == XML_ELEMENT_NODE) ||
9174 (cur->type == XML_PI_NODE) ||
9175 (cur->type == XML_COMMENT_NODE) ||
9176 (cur->type == XML_CDATA_SECTION_NODE) ||
9177 (cur->type == XML_TEXT_NODE)))) {
9178 n++;
9179 if (n == indx)
9180 addNode(list, cur);
9181 }
9182 break;
9183 case NODE_TEST_PI:
9184 if (cur->type == XML_PI_NODE) {
9185 if ((name != NULL) &&
9186 (!xmlStrEqual(name, cur->name)))
9187 break;
9188 n++;
9189 if (n == indx)
9190 addNode(list, cur);
9191 }
9192 break;
9193 case NODE_TEST_ALL:
9194 if (axis == AXIS_ATTRIBUTE) {
9195 if (cur->type == XML_ATTRIBUTE_NODE) {
9196 n++;
9197 if (n == indx)
9198 addNode(list, cur);
9199 }
9200 } else if (axis == AXIS_NAMESPACE) {
9201 if (cur->type == XML_NAMESPACE_DECL) {
9202 n++;
9203 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009204 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9205 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009206 }
9207 } else {
9208 if (cur->type == XML_ELEMENT_NODE) {
9209 if (prefix == NULL) {
9210 n++;
9211 if (n == indx)
9212 addNode(list, cur);
9213 } else if ((cur->ns != NULL) &&
9214 (xmlStrEqual(URI, cur->ns->href))) {
9215 n++;
9216 if (n == indx)
9217 addNode(list, cur);
9218 }
9219 }
9220 }
9221 break;
9222 case NODE_TEST_NS:{
9223 TODO;
9224 break;
9225 }
9226 case NODE_TEST_NAME:
9227 switch (cur->type) {
9228 case XML_ELEMENT_NODE:
9229 if (xmlStrEqual(name, cur->name)) {
9230 if (prefix == NULL) {
9231 if (cur->ns == NULL) {
9232 n++;
9233 if (n == indx)
9234 addNode(list, cur);
9235 }
9236 } else {
9237 if ((cur->ns != NULL) &&
9238 (xmlStrEqual(URI,
9239 cur->ns->href))) {
9240 n++;
9241 if (n == indx)
9242 addNode(list, cur);
9243 }
9244 }
9245 }
9246 break;
9247 case XML_ATTRIBUTE_NODE:{
9248 xmlAttrPtr attr = (xmlAttrPtr) cur;
9249
9250 if (xmlStrEqual(name, attr->name)) {
9251 if (prefix == NULL) {
9252 if ((attr->ns == NULL) ||
9253 (attr->ns->prefix == NULL)) {
9254 n++;
9255 if (n == indx)
9256 addNode(list, cur);
9257 }
9258 } else {
9259 if ((attr->ns != NULL) &&
9260 (xmlStrEqual(URI,
9261 attr->ns->
9262 href))) {
9263 n++;
9264 if (n == indx)
9265 addNode(list, cur);
9266 }
9267 }
9268 }
9269 break;
9270 }
9271 case XML_NAMESPACE_DECL:
9272 if (cur->type == XML_NAMESPACE_DECL) {
9273 xmlNsPtr ns = (xmlNsPtr) cur;
9274
9275 if ((ns->prefix != NULL) && (name != NULL)
9276 && (xmlStrEqual(ns->prefix, name))) {
9277 n++;
9278 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009279 xmlXPathNodeSetAddNs(list,
9280 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009281 }
9282 }
9283 break;
9284 default:
9285 break;
9286 }
9287 break;
9288 break;
9289 }
9290 } while (n < indx);
9291 }
9292 ctxt->context->node = tmp;
9293#ifdef DEBUG_STEP_NTH
9294 xmlGenericError(xmlGenericErrorContext,
9295 "\nExamined %d nodes, found %d nodes at that step\n",
9296 t, list->nodeNr);
9297#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009298 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009299 if ((obj->boolval) && (obj->user != NULL)) {
9300 ctxt->value->boolval = 1;
9301 ctxt->value->user = obj->user;
9302 obj->user = NULL;
9303 obj->boolval = 0;
9304 }
9305 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009306 return(t);
9307}
9308
9309/**
9310 * xmlXPathCompOpEvalFirst:
9311 * @ctxt: the XPath parser context with the compiled expression
9312 * @op: an XPath compiled operation
9313 * @first: the first elem found so far
9314 *
9315 * Evaluate the Precompiled XPath operation searching only the first
9316 * element in document order
9317 *
9318 * Returns the number of examined objects.
9319 */
9320static int
9321xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9322 xmlXPathStepOpPtr op, xmlNodePtr * first)
9323{
9324 int total = 0, cur;
9325 xmlXPathCompExprPtr comp;
9326 xmlXPathObjectPtr arg1, arg2;
9327
Daniel Veillard556c6682001-10-06 09:59:51 +00009328 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009329 comp = ctxt->comp;
9330 switch (op->op) {
9331 case XPATH_OP_END:
9332 return (0);
9333 case XPATH_OP_UNION:
9334 total =
9335 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9336 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009337 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009338 if ((ctxt->value != NULL)
9339 && (ctxt->value->type == XPATH_NODESET)
9340 && (ctxt->value->nodesetval != NULL)
9341 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9342 /*
9343 * limit tree traversing to first node in the result
9344 */
9345 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9346 *first = ctxt->value->nodesetval->nodeTab[0];
9347 }
9348 cur =
9349 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9350 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009351 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009352 CHECK_TYPE0(XPATH_NODESET);
9353 arg2 = valuePop(ctxt);
9354
9355 CHECK_TYPE0(XPATH_NODESET);
9356 arg1 = valuePop(ctxt);
9357
9358 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9359 arg2->nodesetval);
9360 valuePush(ctxt, arg1);
9361 xmlXPathFreeObject(arg2);
9362 /* optimizer */
9363 if (total > cur)
9364 xmlXPathCompSwap(op);
9365 return (total + cur);
9366 case XPATH_OP_ROOT:
9367 xmlXPathRoot(ctxt);
9368 return (0);
9369 case XPATH_OP_NODE:
9370 if (op->ch1 != -1)
9371 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009372 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009373 if (op->ch2 != -1)
9374 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009375 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009376 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9377 return (total);
9378 case XPATH_OP_RESET:
9379 if (op->ch1 != -1)
9380 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009381 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009382 if (op->ch2 != -1)
9383 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009384 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009385 ctxt->context->node = NULL;
9386 return (total);
9387 case XPATH_OP_COLLECT:{
9388 if (op->ch1 == -1)
9389 return (total);
9390
9391 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009392 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009393
9394 /*
9395 * Optimization for [n] selection where n is a number
9396 */
9397 if ((op->ch2 != -1) &&
9398 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9399 (comp->steps[op->ch2].ch1 == -1) &&
9400 (comp->steps[op->ch2].ch2 != -1) &&
9401 (comp->steps[comp->steps[op->ch2].ch2].op ==
9402 XPATH_OP_VALUE)) {
9403 xmlXPathObjectPtr val;
9404
9405 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9406 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9407 int indx = (int) val->floatval;
9408
9409 if (val->floatval == (float) indx) {
9410 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9411 first, NULL);
9412 return (total);
9413 }
9414 }
9415 }
9416 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9417 return (total);
9418 }
9419 case XPATH_OP_VALUE:
9420 valuePush(ctxt,
9421 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9422 return (0);
9423 case XPATH_OP_SORT:
9424 if (op->ch1 != -1)
9425 total +=
9426 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9427 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009428 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009429 if ((ctxt->value != NULL)
9430 && (ctxt->value->type == XPATH_NODESET)
9431 && (ctxt->value->nodesetval != NULL))
9432 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9433 return (total);
9434 default:
9435 return (xmlXPathCompOpEval(ctxt, op));
9436 }
9437}
9438
9439/**
9440 * xmlXPathCompOpEvalLast:
9441 * @ctxt: the XPath parser context with the compiled expression
9442 * @op: an XPath compiled operation
9443 * @last: the last elem found so far
9444 *
9445 * Evaluate the Precompiled XPath operation searching only the last
9446 * element in document order
9447 *
9448 * Returns the number of node traversed
9449 */
9450static int
9451xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9452 xmlNodePtr * last)
9453{
9454 int total = 0, cur;
9455 xmlXPathCompExprPtr comp;
9456 xmlXPathObjectPtr arg1, arg2;
9457
Daniel Veillard556c6682001-10-06 09:59:51 +00009458 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009459 comp = ctxt->comp;
9460 switch (op->op) {
9461 case XPATH_OP_END:
9462 return (0);
9463 case XPATH_OP_UNION:
9464 total =
9465 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009466 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009467 if ((ctxt->value != NULL)
9468 && (ctxt->value->type == XPATH_NODESET)
9469 && (ctxt->value->nodesetval != NULL)
9470 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9471 /*
9472 * limit tree traversing to first node in the result
9473 */
9474 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9475 *last =
9476 ctxt->value->nodesetval->nodeTab[ctxt->value->
9477 nodesetval->nodeNr -
9478 1];
9479 }
9480 cur =
9481 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009482 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009483 if ((ctxt->value != NULL)
9484 && (ctxt->value->type == XPATH_NODESET)
9485 && (ctxt->value->nodesetval != NULL)
9486 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9487 }
9488 CHECK_TYPE0(XPATH_NODESET);
9489 arg2 = valuePop(ctxt);
9490
9491 CHECK_TYPE0(XPATH_NODESET);
9492 arg1 = valuePop(ctxt);
9493
9494 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9495 arg2->nodesetval);
9496 valuePush(ctxt, arg1);
9497 xmlXPathFreeObject(arg2);
9498 /* optimizer */
9499 if (total > cur)
9500 xmlXPathCompSwap(op);
9501 return (total + cur);
9502 case XPATH_OP_ROOT:
9503 xmlXPathRoot(ctxt);
9504 return (0);
9505 case XPATH_OP_NODE:
9506 if (op->ch1 != -1)
9507 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009508 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009509 if (op->ch2 != -1)
9510 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009511 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009512 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9513 return (total);
9514 case XPATH_OP_RESET:
9515 if (op->ch1 != -1)
9516 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009517 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009518 if (op->ch2 != -1)
9519 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009520 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009521 ctxt->context->node = NULL;
9522 return (total);
9523 case XPATH_OP_COLLECT:{
9524 if (op->ch1 == -1)
9525 return (0);
9526
9527 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009528 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009529
9530 /*
9531 * Optimization for [n] selection where n is a number
9532 */
9533 if ((op->ch2 != -1) &&
9534 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9535 (comp->steps[op->ch2].ch1 == -1) &&
9536 (comp->steps[op->ch2].ch2 != -1) &&
9537 (comp->steps[comp->steps[op->ch2].ch2].op ==
9538 XPATH_OP_VALUE)) {
9539 xmlXPathObjectPtr val;
9540
9541 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9542 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9543 int indx = (int) val->floatval;
9544
9545 if (val->floatval == (float) indx) {
9546 total +=
9547 xmlXPathNodeCollectAndTestNth(ctxt, op,
9548 indx, NULL,
9549 last);
9550 return (total);
9551 }
9552 }
9553 }
9554 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9555 return (total);
9556 }
9557 case XPATH_OP_VALUE:
9558 valuePush(ctxt,
9559 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9560 return (0);
9561 case XPATH_OP_SORT:
9562 if (op->ch1 != -1)
9563 total +=
9564 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9565 last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009566 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009567 if ((ctxt->value != NULL)
9568 && (ctxt->value->type == XPATH_NODESET)
9569 && (ctxt->value->nodesetval != NULL))
9570 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9571 return (total);
9572 default:
9573 return (xmlXPathCompOpEval(ctxt, op));
9574 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009575}
9576
Owen Taylor3473f882001-02-23 17:55:21 +00009577/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009578 * xmlXPathCompOpEval:
9579 * @ctxt: the XPath parser context with the compiled expression
9580 * @op: an XPath compiled operation
9581 *
9582 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009583 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009584 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009585static int
9586xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9587{
9588 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009589 int equal, ret;
9590 xmlXPathCompExprPtr comp;
9591 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009592 xmlNodePtr bak;
9593 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +00009594 int pp;
William M. Brack692092b2002-06-28 15:01:24 +00009595 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009596
Daniel Veillard556c6682001-10-06 09:59:51 +00009597 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009598 comp = ctxt->comp;
9599 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009600 case XPATH_OP_END:
9601 return (0);
9602 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009603 bakd = ctxt->context->doc;
9604 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009605 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009606 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009607 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009608 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009609 xmlXPathBooleanFunction(ctxt, 1);
9610 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9611 return (total);
9612 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009613 ctxt->context->doc = bakd;
9614 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009615 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009616 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009617 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009618 if (ctxt->error) {
9619 xmlXPathFreeObject(arg2);
9620 return(0);
9621 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009622 xmlXPathBooleanFunction(ctxt, 1);
9623 arg1 = valuePop(ctxt);
9624 arg1->boolval &= arg2->boolval;
9625 valuePush(ctxt, arg1);
9626 xmlXPathFreeObject(arg2);
9627 return (total);
9628 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009629 bakd = ctxt->context->doc;
9630 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009631 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009632 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009633 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009634 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009635 xmlXPathBooleanFunction(ctxt, 1);
9636 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9637 return (total);
9638 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009639 ctxt->context->doc = bakd;
9640 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009641 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009642 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009643 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009644 if (ctxt->error) {
9645 xmlXPathFreeObject(arg2);
9646 return(0);
9647 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009648 xmlXPathBooleanFunction(ctxt, 1);
9649 arg1 = valuePop(ctxt);
9650 arg1->boolval |= arg2->boolval;
9651 valuePush(ctxt, arg1);
9652 xmlXPathFreeObject(arg2);
9653 return (total);
9654 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009655 bakd = ctxt->context->doc;
9656 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009657 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009658 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009659 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009660 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009661 ctxt->context->doc = bakd;
9662 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009663 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009664 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009665 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009666 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009667 equal = xmlXPathEqualValues(ctxt);
9668 if (op->value)
9669 valuePush(ctxt, xmlXPathNewBoolean(equal));
9670 else
9671 valuePush(ctxt, xmlXPathNewBoolean(!equal));
9672 return (total);
9673 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009674 bakd = ctxt->context->doc;
9675 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009676 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009677 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009678 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009679 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009680 ctxt->context->doc = bakd;
9681 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009682 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009683 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009684 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009685 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009686 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
9687 valuePush(ctxt, xmlXPathNewBoolean(ret));
9688 return (total);
9689 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009690 bakd = ctxt->context->doc;
9691 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009692 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009693 cs = ctxt->context->contextSize;
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 Veillard7089d6b2002-03-29 17:28:10 +00009696 if (op->ch2 != -1) {
9697 ctxt->context->doc = bakd;
9698 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009699 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009700 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009701 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009702 }
Daniel Veillard556c6682001-10-06 09:59:51 +00009703 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009704 if (op->value == 0)
9705 xmlXPathSubValues(ctxt);
9706 else if (op->value == 1)
9707 xmlXPathAddValues(ctxt);
9708 else if (op->value == 2)
9709 xmlXPathValueFlipSign(ctxt);
9710 else if (op->value == 3) {
9711 CAST_TO_NUMBER;
9712 CHECK_TYPE0(XPATH_NUMBER);
9713 }
9714 return (total);
9715 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009716 bakd = ctxt->context->doc;
9717 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009718 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009719 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009720 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009721 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009722 ctxt->context->doc = bakd;
9723 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009724 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009725 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009726 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009727 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009728 if (op->value == 0)
9729 xmlXPathMultValues(ctxt);
9730 else if (op->value == 1)
9731 xmlXPathDivValues(ctxt);
9732 else if (op->value == 2)
9733 xmlXPathModValues(ctxt);
9734 return (total);
9735 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009736 bakd = ctxt->context->doc;
9737 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009738 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009739 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009740 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009741 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009742 ctxt->context->doc = bakd;
9743 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009744 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009745 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009746 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009747 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009748 CHECK_TYPE0(XPATH_NODESET);
9749 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009750
Daniel Veillardf06307e2001-07-03 10:35:50 +00009751 CHECK_TYPE0(XPATH_NODESET);
9752 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009753
Daniel Veillardf06307e2001-07-03 10:35:50 +00009754 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9755 arg2->nodesetval);
9756 valuePush(ctxt, arg1);
9757 xmlXPathFreeObject(arg2);
9758 return (total);
9759 case XPATH_OP_ROOT:
9760 xmlXPathRoot(ctxt);
9761 return (total);
9762 case XPATH_OP_NODE:
9763 if (op->ch1 != -1)
9764 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009765 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009766 if (op->ch2 != -1)
9767 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009768 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009769 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9770 return (total);
9771 case XPATH_OP_RESET:
9772 if (op->ch1 != -1)
9773 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009774 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009775 if (op->ch2 != -1)
9776 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009777 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009778 ctxt->context->node = NULL;
9779 return (total);
9780 case XPATH_OP_COLLECT:{
9781 if (op->ch1 == -1)
9782 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009783
Daniel Veillardf06307e2001-07-03 10:35:50 +00009784 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009785 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009786
Daniel Veillardf06307e2001-07-03 10:35:50 +00009787 /*
9788 * Optimization for [n] selection where n is a number
9789 */
9790 if ((op->ch2 != -1) &&
9791 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9792 (comp->steps[op->ch2].ch1 == -1) &&
9793 (comp->steps[op->ch2].ch2 != -1) &&
9794 (comp->steps[comp->steps[op->ch2].ch2].op ==
9795 XPATH_OP_VALUE)) {
9796 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +00009797
Daniel Veillardf06307e2001-07-03 10:35:50 +00009798 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9799 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9800 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009801
Daniel Veillardf06307e2001-07-03 10:35:50 +00009802 if (val->floatval == (float) indx) {
9803 total +=
9804 xmlXPathNodeCollectAndTestNth(ctxt, op,
9805 indx, NULL,
9806 NULL);
9807 return (total);
9808 }
9809 }
9810 }
9811 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
9812 return (total);
9813 }
9814 case XPATH_OP_VALUE:
9815 valuePush(ctxt,
9816 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9817 return (total);
9818 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +00009819 xmlXPathObjectPtr val;
9820
Daniel Veillardf06307e2001-07-03 10:35:50 +00009821 if (op->ch1 != -1)
9822 total +=
9823 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009824 if (op->value5 == NULL) {
9825 val = xmlXPathVariableLookup(ctxt->context, op->value4);
9826 if (val == NULL) {
9827 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
9828 return(0);
9829 }
9830 valuePush(ctxt, val);
9831 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009832 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009833
Daniel Veillardf06307e2001-07-03 10:35:50 +00009834 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9835 if (URI == NULL) {
9836 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009837 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009838 op->value4, op->value5);
9839 return (total);
9840 }
Daniel Veillard556c6682001-10-06 09:59:51 +00009841 val = xmlXPathVariableLookupNS(ctxt->context,
9842 op->value4, URI);
9843 if (val == NULL) {
9844 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
9845 return(0);
9846 }
9847 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009848 }
9849 return (total);
9850 }
9851 case XPATH_OP_FUNCTION:{
9852 xmlXPathFunction func;
9853 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +00009854 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009855
9856 if (op->ch1 != -1)
9857 total +=
9858 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009859 if (ctxt->valueNr < op->value) {
9860 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009861 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +00009862 ctxt->error = XPATH_INVALID_OPERAND;
9863 return (total);
9864 }
9865 for (i = 0; i < op->value; i++)
9866 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
9867 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009868 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +00009869 ctxt->error = XPATH_INVALID_OPERAND;
9870 return (total);
9871 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009872 if (op->cache != NULL)
9873 func = (xmlXPathFunction) op->cache;
9874 else {
9875 const xmlChar *URI = NULL;
9876
9877 if (op->value5 == NULL)
9878 func =
9879 xmlXPathFunctionLookup(ctxt->context,
9880 op->value4);
9881 else {
9882 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9883 if (URI == NULL) {
9884 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009885 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009886 op->value4, op->value5);
9887 return (total);
9888 }
9889 func = xmlXPathFunctionLookupNS(ctxt->context,
9890 op->value4, URI);
9891 }
9892 if (func == NULL) {
9893 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009894 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009895 op->value4);
9896 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009897 }
9898 op->cache = (void *) func;
9899 op->cacheURI = (void *) URI;
9900 }
9901 oldFunc = ctxt->context->function;
9902 oldFuncURI = ctxt->context->functionURI;
9903 ctxt->context->function = op->value4;
9904 ctxt->context->functionURI = op->cacheURI;
9905 func(ctxt, op->value);
9906 ctxt->context->function = oldFunc;
9907 ctxt->context->functionURI = oldFuncURI;
9908 return (total);
9909 }
9910 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +00009911 bakd = ctxt->context->doc;
9912 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009913 if (op->ch1 != -1)
9914 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard088bf112002-05-14 11:03:59 +00009915 ctxt->context->doc = bakd;
9916 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +00009917 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009918 if (op->ch2 != -1)
9919 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard088bf112002-05-14 11:03:59 +00009920 ctxt->context->doc = bakd;
9921 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +00009922 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009923 return (total);
9924 case XPATH_OP_PREDICATE:
9925 case XPATH_OP_FILTER:{
9926 xmlXPathObjectPtr res;
9927 xmlXPathObjectPtr obj, tmp;
9928 xmlNodeSetPtr newset = NULL;
9929 xmlNodeSetPtr oldset;
9930 xmlNodePtr oldnode;
9931 int i;
9932
9933 /*
9934 * Optimization for ()[1] selection i.e. the first elem
9935 */
9936 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9937 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9938 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
9939 xmlXPathObjectPtr val;
9940
9941 val = comp->steps[op->ch2].value4;
9942 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
9943 (val->floatval == 1.0)) {
9944 xmlNodePtr first = NULL;
9945
9946 total +=
9947 xmlXPathCompOpEvalFirst(ctxt,
9948 &comp->steps[op->ch1],
9949 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009950 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009951 /*
9952 * The nodeset should be in document order,
9953 * Keep only the first value
9954 */
9955 if ((ctxt->value != NULL) &&
9956 (ctxt->value->type == XPATH_NODESET) &&
9957 (ctxt->value->nodesetval != NULL) &&
9958 (ctxt->value->nodesetval->nodeNr > 1))
9959 ctxt->value->nodesetval->nodeNr = 1;
9960 return (total);
9961 }
9962 }
9963 /*
9964 * Optimization for ()[last()] selection i.e. the last elem
9965 */
9966 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9967 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9968 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
9969 int f = comp->steps[op->ch2].ch1;
9970
9971 if ((f != -1) &&
9972 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
9973 (comp->steps[f].value5 == NULL) &&
9974 (comp->steps[f].value == 0) &&
9975 (comp->steps[f].value4 != NULL) &&
9976 (xmlStrEqual
9977 (comp->steps[f].value4, BAD_CAST "last"))) {
9978 xmlNodePtr last = NULL;
9979
9980 total +=
9981 xmlXPathCompOpEvalLast(ctxt,
9982 &comp->steps[op->ch1],
9983 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009984 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009985 /*
9986 * The nodeset should be in document order,
9987 * Keep only the last value
9988 */
9989 if ((ctxt->value != NULL) &&
9990 (ctxt->value->type == XPATH_NODESET) &&
9991 (ctxt->value->nodesetval != NULL) &&
9992 (ctxt->value->nodesetval->nodeTab != NULL) &&
9993 (ctxt->value->nodesetval->nodeNr > 1)) {
9994 ctxt->value->nodesetval->nodeTab[0] =
9995 ctxt->value->nodesetval->nodeTab[ctxt->
9996 value->
9997 nodesetval->
9998 nodeNr -
9999 1];
10000 ctxt->value->nodesetval->nodeNr = 1;
10001 }
10002 return (total);
10003 }
10004 }
10005
10006 if (op->ch1 != -1)
10007 total +=
10008 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010009 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010010 if (op->ch2 == -1)
10011 return (total);
10012 if (ctxt->value == NULL)
10013 return (total);
10014
10015 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010016
10017#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010018 /*
10019 * Hum are we filtering the result of an XPointer expression
10020 */
10021 if (ctxt->value->type == XPATH_LOCATIONSET) {
10022 xmlLocationSetPtr newlocset = NULL;
10023 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010024
Daniel Veillardf06307e2001-07-03 10:35:50 +000010025 /*
10026 * Extract the old locset, and then evaluate the result of the
10027 * expression for all the element in the locset. use it to grow
10028 * up a new locset.
10029 */
10030 CHECK_TYPE0(XPATH_LOCATIONSET);
10031 obj = valuePop(ctxt);
10032 oldlocset = obj->user;
10033 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010034
Daniel Veillardf06307e2001-07-03 10:35:50 +000010035 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10036 ctxt->context->contextSize = 0;
10037 ctxt->context->proximityPosition = 0;
10038 if (op->ch2 != -1)
10039 total +=
10040 xmlXPathCompOpEval(ctxt,
10041 &comp->steps[op->ch2]);
10042 res = valuePop(ctxt);
10043 if (res != NULL)
10044 xmlXPathFreeObject(res);
10045 valuePush(ctxt, obj);
10046 CHECK_ERROR0;
10047 return (total);
10048 }
10049 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010050
Daniel Veillardf06307e2001-07-03 10:35:50 +000010051 for (i = 0; i < oldlocset->locNr; i++) {
10052 /*
10053 * Run the evaluation with a node list made of a
10054 * single item in the nodelocset.
10055 */
10056 ctxt->context->node = oldlocset->locTab[i]->user;
10057 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10058 valuePush(ctxt, tmp);
10059 ctxt->context->contextSize = oldlocset->locNr;
10060 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010061
Daniel Veillardf06307e2001-07-03 10:35:50 +000010062 if (op->ch2 != -1)
10063 total +=
10064 xmlXPathCompOpEval(ctxt,
10065 &comp->steps[op->ch2]);
10066 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010067
Daniel Veillardf06307e2001-07-03 10:35:50 +000010068 /*
10069 * The result of the evaluation need to be tested to
10070 * decided whether the filter succeeded or not
10071 */
10072 res = valuePop(ctxt);
10073 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10074 xmlXPtrLocationSetAdd(newlocset,
10075 xmlXPathObjectCopy
10076 (oldlocset->locTab[i]));
10077 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010078
Daniel Veillardf06307e2001-07-03 10:35:50 +000010079 /*
10080 * Cleanup
10081 */
10082 if (res != NULL)
10083 xmlXPathFreeObject(res);
10084 if (ctxt->value == tmp) {
10085 res = valuePop(ctxt);
10086 xmlXPathFreeObject(res);
10087 }
10088
10089 ctxt->context->node = NULL;
10090 }
10091
10092 /*
10093 * The result is used as the new evaluation locset.
10094 */
10095 xmlXPathFreeObject(obj);
10096 ctxt->context->node = NULL;
10097 ctxt->context->contextSize = -1;
10098 ctxt->context->proximityPosition = -1;
10099 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10100 ctxt->context->node = oldnode;
10101 return (total);
10102 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010103#endif /* LIBXML_XPTR_ENABLED */
10104
Daniel Veillardf06307e2001-07-03 10:35:50 +000010105 /*
10106 * Extract the old set, and then evaluate the result of the
10107 * expression for all the element in the set. use it to grow
10108 * up a new set.
10109 */
10110 CHECK_TYPE0(XPATH_NODESET);
10111 obj = valuePop(ctxt);
10112 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010113
Daniel Veillardf06307e2001-07-03 10:35:50 +000010114 oldnode = ctxt->context->node;
10115 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010116
Daniel Veillardf06307e2001-07-03 10:35:50 +000010117 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10118 ctxt->context->contextSize = 0;
10119 ctxt->context->proximityPosition = 0;
10120 if (op->ch2 != -1)
10121 total +=
10122 xmlXPathCompOpEval(ctxt,
10123 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010124 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010125 res = valuePop(ctxt);
10126 if (res != NULL)
10127 xmlXPathFreeObject(res);
10128 valuePush(ctxt, obj);
10129 ctxt->context->node = oldnode;
10130 CHECK_ERROR0;
10131 } else {
10132 /*
10133 * Initialize the new set.
10134 */
10135 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010136
Daniel Veillardf06307e2001-07-03 10:35:50 +000010137 for (i = 0; i < oldset->nodeNr; i++) {
10138 /*
10139 * Run the evaluation with a node list made of
10140 * a single item in the nodeset.
10141 */
10142 ctxt->context->node = oldset->nodeTab[i];
10143 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10144 valuePush(ctxt, tmp);
10145 ctxt->context->contextSize = oldset->nodeNr;
10146 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010147
Daniel Veillardf06307e2001-07-03 10:35:50 +000010148 if (op->ch2 != -1)
10149 total +=
10150 xmlXPathCompOpEval(ctxt,
10151 &comp->steps[op->ch2]);
10152 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010153
Daniel Veillardf06307e2001-07-03 10:35:50 +000010154 /*
10155 * The result of the evaluation need to be tested to
10156 * decided whether the filter succeeded or not
10157 */
10158 res = valuePop(ctxt);
10159 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10160 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10161 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010162
Daniel Veillardf06307e2001-07-03 10:35:50 +000010163 /*
10164 * Cleanup
10165 */
10166 if (res != NULL)
10167 xmlXPathFreeObject(res);
10168 if (ctxt->value == tmp) {
10169 res = valuePop(ctxt);
10170 xmlXPathFreeObject(res);
10171 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010172
Daniel Veillardf06307e2001-07-03 10:35:50 +000010173 ctxt->context->node = NULL;
10174 }
10175
10176 /*
10177 * The result is used as the new evaluation set.
10178 */
10179 xmlXPathFreeObject(obj);
10180 ctxt->context->node = NULL;
10181 ctxt->context->contextSize = -1;
10182 ctxt->context->proximityPosition = -1;
10183 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10184 }
10185 ctxt->context->node = oldnode;
10186 return (total);
10187 }
10188 case XPATH_OP_SORT:
10189 if (op->ch1 != -1)
10190 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010191 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010192 if ((ctxt->value != NULL) &&
10193 (ctxt->value->type == XPATH_NODESET) &&
10194 (ctxt->value->nodesetval != NULL))
10195 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10196 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010197#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010198 case XPATH_OP_RANGETO:{
10199 xmlXPathObjectPtr range;
10200 xmlXPathObjectPtr res, obj;
10201 xmlXPathObjectPtr tmp;
10202 xmlLocationSetPtr newset = NULL;
10203 xmlNodeSetPtr oldset;
10204 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010205
Daniel Veillardf06307e2001-07-03 10:35:50 +000010206 if (op->ch1 != -1)
10207 total +=
10208 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10209 if (op->ch2 == -1)
10210 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010211
Daniel Veillardf06307e2001-07-03 10:35:50 +000010212 CHECK_TYPE0(XPATH_NODESET);
10213 obj = valuePop(ctxt);
10214 oldset = obj->nodesetval;
10215 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010216
Daniel Veillardf06307e2001-07-03 10:35:50 +000010217 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010218
Daniel Veillardf06307e2001-07-03 10:35:50 +000010219 if (oldset != NULL) {
10220 for (i = 0; i < oldset->nodeNr; i++) {
10221 /*
10222 * Run the evaluation with a node list made of a single item
10223 * in the nodeset.
10224 */
10225 ctxt->context->node = oldset->nodeTab[i];
10226 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10227 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010228
Daniel Veillardf06307e2001-07-03 10:35:50 +000010229 if (op->ch2 != -1)
10230 total +=
10231 xmlXPathCompOpEval(ctxt,
10232 &comp->steps[op->ch2]);
10233 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010234
Daniel Veillardf06307e2001-07-03 10:35:50 +000010235 /*
10236 * The result of the evaluation need to be tested to
10237 * decided whether the filter succeeded or not
10238 */
10239 res = valuePop(ctxt);
10240 range =
10241 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10242 res);
10243 if (range != NULL) {
10244 xmlXPtrLocationSetAdd(newset, range);
10245 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010246
Daniel Veillardf06307e2001-07-03 10:35:50 +000010247 /*
10248 * Cleanup
10249 */
10250 if (res != NULL)
10251 xmlXPathFreeObject(res);
10252 if (ctxt->value == tmp) {
10253 res = valuePop(ctxt);
10254 xmlXPathFreeObject(res);
10255 }
10256
10257 ctxt->context->node = NULL;
10258 }
10259 }
10260
10261 /*
10262 * The result is used as the new evaluation set.
10263 */
10264 xmlXPathFreeObject(obj);
10265 ctxt->context->node = NULL;
10266 ctxt->context->contextSize = -1;
10267 ctxt->context->proximityPosition = -1;
10268 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
10269 return (total);
10270 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010271#endif /* LIBXML_XPTR_ENABLED */
10272 }
10273 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010274 "XPath: unknown precompiled operation %d\n", op->op);
10275 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010276}
10277
10278/**
10279 * xmlXPathRunEval:
10280 * @ctxt: the XPath parser context with the compiled expression
10281 *
10282 * Evaluate the Precompiled XPath expression in the given context.
10283 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010284static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010285xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10286 xmlXPathCompExprPtr comp;
10287
10288 if ((ctxt == NULL) || (ctxt->comp == NULL))
10289 return;
10290
10291 if (ctxt->valueTab == NULL) {
10292 /* Allocate the value stack */
10293 ctxt->valueTab = (xmlXPathObjectPtr *)
10294 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10295 if (ctxt->valueTab == NULL) {
10296 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010297 }
10298 ctxt->valueNr = 0;
10299 ctxt->valueMax = 10;
10300 ctxt->value = NULL;
10301 }
10302 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000010303 if(comp->last < 0) {
10304 xmlGenericError(xmlGenericErrorContext,
10305 "xmlXPathRunEval: last is less than zero\n");
10306 return;
10307 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010308 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10309}
10310
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010311/************************************************************************
10312 * *
10313 * Public interfaces *
10314 * *
10315 ************************************************************************/
10316
10317/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010318 * xmlXPathEvalPredicate:
10319 * @ctxt: the XPath context
10320 * @res: the Predicate Expression evaluation result
10321 *
10322 * Evaluate a predicate result for the current node.
10323 * A PredicateExpr is evaluated by evaluating the Expr and converting
10324 * the result to a boolean. If the result is a number, the result will
10325 * be converted to true if the number is equal to the position of the
10326 * context node in the context node list (as returned by the position
10327 * function) and will be converted to false otherwise; if the result
10328 * is not a number, then the result will be converted as if by a call
10329 * to the boolean function.
10330 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010331 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010332 */
10333int
10334xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
10335 if (res == NULL) return(0);
10336 switch (res->type) {
10337 case XPATH_BOOLEAN:
10338 return(res->boolval);
10339 case XPATH_NUMBER:
10340 return(res->floatval == ctxt->proximityPosition);
10341 case XPATH_NODESET:
10342 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010343 if (res->nodesetval == NULL)
10344 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010345 return(res->nodesetval->nodeNr != 0);
10346 case XPATH_STRING:
10347 return((res->stringval != NULL) &&
10348 (xmlStrlen(res->stringval) != 0));
10349 default:
10350 STRANGE
10351 }
10352 return(0);
10353}
10354
10355/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010356 * xmlXPathEvaluatePredicateResult:
10357 * @ctxt: the XPath Parser context
10358 * @res: the Predicate Expression evaluation result
10359 *
10360 * Evaluate a predicate result for the current node.
10361 * A PredicateExpr is evaluated by evaluating the Expr and converting
10362 * the result to a boolean. If the result is a number, the result will
10363 * be converted to true if the number is equal to the position of the
10364 * context node in the context node list (as returned by the position
10365 * function) and will be converted to false otherwise; if the result
10366 * is not a number, then the result will be converted as if by a call
10367 * to the boolean function.
10368 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010369 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010370 */
10371int
10372xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10373 xmlXPathObjectPtr res) {
10374 if (res == NULL) return(0);
10375 switch (res->type) {
10376 case XPATH_BOOLEAN:
10377 return(res->boolval);
10378 case XPATH_NUMBER:
10379 return(res->floatval == ctxt->context->proximityPosition);
10380 case XPATH_NODESET:
10381 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000010382 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000010383 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010384 return(res->nodesetval->nodeNr != 0);
10385 case XPATH_STRING:
10386 return((res->stringval != NULL) &&
10387 (xmlStrlen(res->stringval) != 0));
10388 default:
10389 STRANGE
10390 }
10391 return(0);
10392}
10393
10394/**
10395 * xmlXPathCompile:
10396 * @str: the XPath expression
10397 *
10398 * Compile an XPath expression
10399 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010400 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010401 * the caller has to free the object.
10402 */
10403xmlXPathCompExprPtr
10404xmlXPathCompile(const xmlChar *str) {
10405 xmlXPathParserContextPtr ctxt;
10406 xmlXPathCompExprPtr comp;
10407
10408 xmlXPathInit();
10409
10410 ctxt = xmlXPathNewParserContext(str, NULL);
10411 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010412
Daniel Veillard40af6492001-04-22 08:50:55 +000010413 if (*ctxt->cur != 0) {
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010414 /*
10415 * aleksey: in some cases this line prints *second* error message
10416 * (see bug #78858) and probably this should be fixed.
10417 * However, we are not sure that all error messages are printed
10418 * out in other places. It's not critical so we leave it as-is for now
10419 */
Daniel Veillard40af6492001-04-22 08:50:55 +000010420 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10421 comp = NULL;
10422 } else {
10423 comp = ctxt->comp;
10424 ctxt->comp = NULL;
10425 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010426 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010427#ifdef DEBUG_EVAL_COUNTS
10428 if (comp != NULL) {
10429 comp->string = xmlStrdup(str);
10430 comp->nb = 0;
10431 }
10432#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010433 return(comp);
10434}
10435
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010436/**
10437 * xmlXPathCompiledEval:
10438 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000010439 * @ctx: the XPath context
10440 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010441 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000010442 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010443 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000010444 * the caller has to free the object.
10445 */
10446xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010447xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000010448 xmlXPathParserContextPtr ctxt;
10449 xmlXPathObjectPtr res, tmp, init = NULL;
10450 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000010451#ifndef LIBXML_THREAD_ENABLED
10452 static int reentance = 0;
10453#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010454
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010455 if ((comp == NULL) || (ctx == NULL))
10456 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010457 xmlXPathInit();
10458
10459 CHECK_CONTEXT(ctx)
10460
Daniel Veillard81463942001-10-16 12:34:39 +000010461#ifndef LIBXML_THREAD_ENABLED
10462 reentance++;
10463 if (reentance > 1)
10464 xmlXPathDisableOptimizer = 1;
10465#endif
10466
Daniel Veillardf06307e2001-07-03 10:35:50 +000010467#ifdef DEBUG_EVAL_COUNTS
10468 comp->nb++;
10469 if ((comp->string != NULL) && (comp->nb > 100)) {
10470 fprintf(stderr, "100 x %s\n", comp->string);
10471 comp->nb = 0;
10472 }
10473#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010474 ctxt = xmlXPathCompParserContext(comp, ctx);
10475 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010476
10477 if (ctxt->value == NULL) {
10478 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010479 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000010480 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000010481 } else {
10482 res = valuePop(ctxt);
10483 }
10484
Daniel Veillardf06307e2001-07-03 10:35:50 +000010485
Owen Taylor3473f882001-02-23 17:55:21 +000010486 do {
10487 tmp = valuePop(ctxt);
10488 if (tmp != NULL) {
10489 if (tmp != init)
10490 stack++;
10491 xmlXPathFreeObject(tmp);
10492 }
10493 } while (tmp != NULL);
10494 if ((stack != 0) && (res != NULL)) {
10495 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010496 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000010497 stack);
10498 }
10499 if (ctxt->error != XPATH_EXPRESSION_OK) {
10500 xmlXPathFreeObject(res);
10501 res = NULL;
10502 }
10503
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010504
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010505 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010506 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000010507#ifndef LIBXML_THREAD_ENABLED
10508 reentance--;
10509#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010510 return(res);
10511}
10512
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010513/**
10514 * xmlXPathEvalExpr:
10515 * @ctxt: the XPath Parser context
10516 *
10517 * Parse and evaluate an XPath expression in the given context,
10518 * then push the result on the context stack
10519 */
10520void
10521xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
10522 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010523 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010524 xmlXPathRunEval(ctxt);
10525}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010526
10527/**
10528 * xmlXPathEval:
10529 * @str: the XPath expression
10530 * @ctx: the XPath context
10531 *
10532 * Evaluate the XPath Location Path in the given context.
10533 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010534 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010535 * the caller has to free the object.
10536 */
10537xmlXPathObjectPtr
10538xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
10539 xmlXPathParserContextPtr ctxt;
10540 xmlXPathObjectPtr res, tmp, init = NULL;
10541 int stack = 0;
10542
10543 xmlXPathInit();
10544
10545 CHECK_CONTEXT(ctx)
10546
10547 ctxt = xmlXPathNewParserContext(str, ctx);
10548 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010549
10550 if (ctxt->value == NULL) {
10551 xmlGenericError(xmlGenericErrorContext,
10552 "xmlXPathEval: evaluation failed\n");
10553 res = NULL;
10554 } else if (*ctxt->cur != 0) {
10555 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10556 res = NULL;
10557 } else {
10558 res = valuePop(ctxt);
10559 }
10560
10561 do {
10562 tmp = valuePop(ctxt);
10563 if (tmp != NULL) {
10564 if (tmp != init)
10565 stack++;
10566 xmlXPathFreeObject(tmp);
10567 }
10568 } while (tmp != NULL);
10569 if ((stack != 0) && (res != NULL)) {
10570 xmlGenericError(xmlGenericErrorContext,
10571 "xmlXPathEval: %d object left on the stack\n",
10572 stack);
10573 }
10574 if (ctxt->error != XPATH_EXPRESSION_OK) {
10575 xmlXPathFreeObject(res);
10576 res = NULL;
10577 }
10578
Owen Taylor3473f882001-02-23 17:55:21 +000010579 xmlXPathFreeParserContext(ctxt);
10580 return(res);
10581}
10582
10583/**
10584 * xmlXPathEvalExpression:
10585 * @str: the XPath expression
10586 * @ctxt: the XPath context
10587 *
10588 * Evaluate the XPath expression in the given context.
10589 *
10590 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
10591 * the caller has to free the object.
10592 */
10593xmlXPathObjectPtr
10594xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
10595 xmlXPathParserContextPtr pctxt;
10596 xmlXPathObjectPtr res, tmp;
10597 int stack = 0;
10598
10599 xmlXPathInit();
10600
10601 CHECK_CONTEXT(ctxt)
10602
10603 pctxt = xmlXPathNewParserContext(str, ctxt);
10604 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010605
10606 if (*pctxt->cur != 0) {
10607 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10608 res = NULL;
10609 } else {
10610 res = valuePop(pctxt);
10611 }
10612 do {
10613 tmp = valuePop(pctxt);
10614 if (tmp != NULL) {
10615 xmlXPathFreeObject(tmp);
10616 stack++;
10617 }
10618 } while (tmp != NULL);
10619 if ((stack != 0) && (res != NULL)) {
10620 xmlGenericError(xmlGenericErrorContext,
10621 "xmlXPathEvalExpression: %d object left on the stack\n",
10622 stack);
10623 }
10624 xmlXPathFreeParserContext(pctxt);
10625 return(res);
10626}
10627
10628/**
10629 * xmlXPathRegisterAllFunctions:
10630 * @ctxt: the XPath context
10631 *
10632 * Registers all default XPath functions in this context
10633 */
10634void
10635xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
10636{
10637 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
10638 xmlXPathBooleanFunction);
10639 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
10640 xmlXPathCeilingFunction);
10641 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
10642 xmlXPathCountFunction);
10643 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
10644 xmlXPathConcatFunction);
10645 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
10646 xmlXPathContainsFunction);
10647 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
10648 xmlXPathIdFunction);
10649 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
10650 xmlXPathFalseFunction);
10651 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
10652 xmlXPathFloorFunction);
10653 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
10654 xmlXPathLastFunction);
10655 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
10656 xmlXPathLangFunction);
10657 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
10658 xmlXPathLocalNameFunction);
10659 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
10660 xmlXPathNotFunction);
10661 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
10662 xmlXPathNameFunction);
10663 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
10664 xmlXPathNamespaceURIFunction);
10665 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
10666 xmlXPathNormalizeFunction);
10667 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
10668 xmlXPathNumberFunction);
10669 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
10670 xmlXPathPositionFunction);
10671 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
10672 xmlXPathRoundFunction);
10673 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
10674 xmlXPathStringFunction);
10675 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
10676 xmlXPathStringLengthFunction);
10677 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
10678 xmlXPathStartsWithFunction);
10679 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
10680 xmlXPathSubstringFunction);
10681 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
10682 xmlXPathSubstringBeforeFunction);
10683 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
10684 xmlXPathSubstringAfterFunction);
10685 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
10686 xmlXPathSumFunction);
10687 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
10688 xmlXPathTrueFunction);
10689 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
10690 xmlXPathTranslateFunction);
10691}
10692
10693#endif /* LIBXML_XPATH_ENABLED */