blob: 9de5bc9d7cd6baa3cf8292b7c2631488007c1556 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * xpath.c: XML Path Language implementation
3 * XPath is a language for addressing parts of an XML document,
4 * designed to be used by both XSLT and XPointer
5 *
6 * Reference: W3C Recommendation 16 November 1999
7 * http://www.w3.org/TR/1999/REC-xpath-19991116
8 * Public reference:
9 * http://www.w3.org/TR/xpath
10 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011 * See Copyright for the status of this software
Owen Taylor3473f882001-02-23 17:55:21 +000012 *
Daniel Veillardc5d64342001-06-24 12:13:24 +000013 * Author: daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000014 *
15 * 14 Nov 2000 ht - truncated declaration of xmlXPathEvalRelativeLocationPath
16 * for VMS
17 */
18
Daniel Veillard34ce8be2002-03-18 19:37:11 +000019#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000020#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000021#ifdef LIBXML_XPATH_ENABLED
22
Owen Taylor3473f882001-02-23 17:55:21 +000023#include <string.h>
24
25#ifdef HAVE_SYS_TYPES_H
26#include <sys/types.h>
27#endif
28#ifdef HAVE_MATH_H
29#include <math.h>
30#endif
31#ifdef HAVE_FLOAT_H
32#include <float.h>
33#endif
Owen Taylor3473f882001-02-23 17:55:21 +000034#ifdef HAVE_CTYPE_H
35#include <ctype.h>
36#endif
Daniel Veillard5792e162001-04-30 17:44:45 +000037#ifdef HAVE_SIGNAL_H
Daniel Veillardb45c43b2001-04-28 17:02:11 +000038#include <signal.h>
Daniel Veillardb45c43b2001-04-28 17:02:11 +000039#endif
Owen Taylor3473f882001-02-23 17:55:21 +000040
41#include <libxml/xmlmemory.h>
42#include <libxml/tree.h>
43#include <libxml/valid.h>
44#include <libxml/xpath.h>
45#include <libxml/xpathInternals.h>
46#include <libxml/parserInternals.h>
47#include <libxml/hash.h>
48#ifdef LIBXML_XPTR_ENABLED
49#include <libxml/xpointer.h>
50#endif
51#ifdef LIBXML_DEBUG_ENABLED
52#include <libxml/debugXML.h>
53#endif
54#include <libxml/xmlerror.h>
Daniel Veillard81463942001-10-16 12:34:39 +000055#include <libxml/threads.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000056#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000057
58/* #define DEBUG */
59/* #define DEBUG_STEP */
Daniel Veillardf06307e2001-07-03 10:35:50 +000060/* #define DEBUG_STEP_NTH */
Owen Taylor3473f882001-02-23 17:55:21 +000061/* #define DEBUG_EXPR */
Daniel Veillardf06307e2001-07-03 10:35:50 +000062/* #define DEBUG_EVAL_COUNTS */
Owen Taylor3473f882001-02-23 17:55:21 +000063
Daniel Veillard5792e162001-04-30 17:44:45 +000064double xmlXPathDivideBy(double f, double fzero);
Owen Taylor3473f882001-02-23 17:55:21 +000065
Daniel Veillard20ee8c02001-10-05 09:18:14 +000066static xmlNs xmlXPathXMLNamespaceStruct = {
67 NULL,
68 XML_NAMESPACE_DECL,
69 XML_XML_NAMESPACE,
70 BAD_CAST "xml"
71};
72static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
Daniel Veillard81463942001-10-16 12:34:39 +000073#ifndef LIBXML_THREADS_ENABLED
74/*
75 * Optimizer is disabled only when threaded apps are detected while
76 * the library ain't compiled for thread safety.
77 */
78static int xmlXPathDisableOptimizer = 0;
79#endif
Daniel Veillard20ee8c02001-10-05 09:18:14 +000080
Daniel Veillard9e7160d2001-03-18 23:17:47 +000081/************************************************************************
82 * *
83 * Floating point stuff *
84 * *
85 ************************************************************************/
86
Daniel Veillardc0631a62001-09-20 13:56:06 +000087#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +000088#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +000089#endif
Daniel Veillardcda96922001-08-21 10:56:31 +000090#include "trionan.c"
91
Owen Taylor3473f882001-02-23 17:55:21 +000092/*
Owen Taylor3473f882001-02-23 17:55:21 +000093 * The lack of portability of this section of the libc is annoying !
94 */
95double xmlXPathNAN = 0;
96double xmlXPathPINF = 1;
97double xmlXPathNINF = -1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +000098double xmlXPathNZERO = 0;
Daniel Veillard20ee8c02001-10-05 09:18:14 +000099static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000100
Owen Taylor3473f882001-02-23 17:55:21 +0000101/**
102 * xmlXPathInit:
103 *
104 * Initialize the XPath environment
105 */
106void
107xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000108 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +0000109
Bjorn Reese45029602001-08-21 09:23:53 +0000110 xmlXPathPINF = trio_pinf();
111 xmlXPathNINF = trio_ninf();
112 xmlXPathNAN = trio_nan();
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000113 xmlXPathNZERO = trio_nzero();
Owen Taylor3473f882001-02-23 17:55:21 +0000114
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000115 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000116}
117
Daniel Veillardcda96922001-08-21 10:56:31 +0000118/**
119 * xmlXPathIsNaN:
120 * @val: a double value
121 *
122 * Provides a portable isnan() function to detect whether a double
123 * is a NotaNumber. Based on trio code
124 * http://sourceforge.net/projects/ctrio/
125 *
126 * Returns 1 if the value is a NaN, 0 otherwise
127 */
128int
129xmlXPathIsNaN(double val) {
130 return(trio_isnan(val));
131}
132
133/**
134 * xmlXPathIsInf:
135 * @val: a double value
136 *
137 * Provides a portable isinf() function to detect whether a double
138 * is a +Infinite or -Infinite. Based on trio code
139 * http://sourceforge.net/projects/ctrio/
140 *
141 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
142 */
143int
144xmlXPathIsInf(double val) {
145 return(trio_isinf(val));
146}
147
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000148/**
149 * xmlXPathGetSign:
150 * @val: a double value
151 *
152 * Provides a portable function to detect the sign of a double
153 * Modified from trio code
154 * http://sourceforge.net/projects/ctrio/
155 *
156 * Returns 1 if the value is Negative, 0 if positive
157 */
Daniel Veillard21458c82002-03-27 16:12:22 +0000158static int
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000159xmlXPathGetSign(double val) {
Daniel Veillard21458c82002-03-27 16:12:22 +0000160 return(trio_signbit(val));
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000161}
162
163
Owen Taylor3473f882001-02-23 17:55:21 +0000164/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000165 * *
166 * Parser Types *
167 * *
168 ************************************************************************/
169
170/*
171 * Types are private:
172 */
173
174typedef enum {
175 XPATH_OP_END=0,
176 XPATH_OP_AND,
177 XPATH_OP_OR,
178 XPATH_OP_EQUAL,
179 XPATH_OP_CMP,
180 XPATH_OP_PLUS,
181 XPATH_OP_MULT,
182 XPATH_OP_UNION,
183 XPATH_OP_ROOT,
184 XPATH_OP_NODE,
185 XPATH_OP_RESET,
186 XPATH_OP_COLLECT,
187 XPATH_OP_VALUE,
188 XPATH_OP_VARIABLE,
189 XPATH_OP_FUNCTION,
190 XPATH_OP_ARG,
191 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000192 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000193 XPATH_OP_SORT
194#ifdef LIBXML_XPTR_ENABLED
195 ,XPATH_OP_RANGETO
196#endif
197} xmlXPathOp;
198
199typedef enum {
200 AXIS_ANCESTOR = 1,
201 AXIS_ANCESTOR_OR_SELF,
202 AXIS_ATTRIBUTE,
203 AXIS_CHILD,
204 AXIS_DESCENDANT,
205 AXIS_DESCENDANT_OR_SELF,
206 AXIS_FOLLOWING,
207 AXIS_FOLLOWING_SIBLING,
208 AXIS_NAMESPACE,
209 AXIS_PARENT,
210 AXIS_PRECEDING,
211 AXIS_PRECEDING_SIBLING,
212 AXIS_SELF
213} xmlXPathAxisVal;
214
215typedef enum {
216 NODE_TEST_NONE = 0,
217 NODE_TEST_TYPE = 1,
218 NODE_TEST_PI = 2,
219 NODE_TEST_ALL = 3,
220 NODE_TEST_NS = 4,
221 NODE_TEST_NAME = 5
222} xmlXPathTestVal;
223
224typedef enum {
225 NODE_TYPE_NODE = 0,
226 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
227 NODE_TYPE_TEXT = XML_TEXT_NODE,
228 NODE_TYPE_PI = XML_PI_NODE
229} xmlXPathTypeVal;
230
231
232typedef struct _xmlXPathStepOp xmlXPathStepOp;
233typedef xmlXPathStepOp *xmlXPathStepOpPtr;
234struct _xmlXPathStepOp {
235 xmlXPathOp op;
236 int ch1;
237 int ch2;
238 int value;
239 int value2;
240 int value3;
241 void *value4;
242 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000243 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000244 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000245};
246
247struct _xmlXPathCompExpr {
248 int nbStep;
249 int maxStep;
250 xmlXPathStepOp *steps; /* ops for computation */
251 int last;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000252#ifdef DEBUG_EVAL_COUNTS
253 int nb;
254 xmlChar *string;
255#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000256};
257
258/************************************************************************
259 * *
260 * Parser Type functions *
261 * *
262 ************************************************************************/
263
264/**
265 * xmlXPathNewCompExpr:
266 *
267 * Create a new Xpath component
268 *
269 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
270 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000271static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000272xmlXPathNewCompExpr(void) {
273 xmlXPathCompExprPtr cur;
274
275 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
276 if (cur == NULL) {
277 xmlGenericError(xmlGenericErrorContext,
278 "xmlXPathNewCompExpr : malloc failed\n");
279 return(NULL);
280 }
281 memset(cur, 0, sizeof(xmlXPathCompExpr));
282 cur->maxStep = 10;
283 cur->nbStep = 0;
284 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
285 sizeof(xmlXPathStepOp));
286 if (cur->steps == NULL) {
287 xmlGenericError(xmlGenericErrorContext,
288 "xmlXPathNewCompExpr : malloc failed\n");
289 xmlFree(cur);
290 return(NULL);
291 }
292 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
293 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000294#ifdef DEBUG_EVAL_COUNTS
295 cur->nb = 0;
296#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000297 return(cur);
298}
299
300/**
301 * xmlXPathFreeCompExpr:
302 * @comp: an XPATH comp
303 *
304 * Free up the memory allocated by @comp
305 */
306void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000307xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
308{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000309 xmlXPathStepOpPtr op;
310 int i;
311
312 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000313 return;
314 for (i = 0; i < comp->nbStep; i++) {
315 op = &comp->steps[i];
316 if (op->value4 != NULL) {
317 if (op->op == XPATH_OP_VALUE)
318 xmlXPathFreeObject(op->value4);
319 else
320 xmlFree(op->value4);
321 }
322 if (op->value5 != NULL)
323 xmlFree(op->value5);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000324 }
325 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000326 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000327 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000328#ifdef DEBUG_EVAL_COUNTS
329 if (comp->string != NULL) {
330 xmlFree(comp->string);
331 }
332#endif
333
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000334 xmlFree(comp);
335}
336
337/**
338 * xmlXPathCompExprAdd:
339 * @comp: the compiled expression
340 * @ch1: first child index
341 * @ch2: second child index
342 * @op: an op
343 * @value: the first int value
344 * @value2: the second int value
345 * @value3: the third int value
346 * @value4: the first string value
347 * @value5: the second string value
348 *
349 * Add an step to an XPath Compiled Expression
350 *
351 * Returns -1 in case of failure, the index otherwise
352 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000353static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000354xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
355 xmlXPathOp op, int value,
356 int value2, int value3, void *value4, void *value5) {
357 if (comp->nbStep >= comp->maxStep) {
358 xmlXPathStepOp *real;
359
360 comp->maxStep *= 2;
361 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
362 comp->maxStep * sizeof(xmlXPathStepOp));
363 if (real == NULL) {
364 comp->maxStep /= 2;
365 xmlGenericError(xmlGenericErrorContext,
366 "xmlXPathCompExprAdd : realloc failed\n");
367 return(-1);
368 }
369 comp->steps = real;
370 }
371 comp->last = comp->nbStep;
372 comp->steps[comp->nbStep].ch1 = ch1;
373 comp->steps[comp->nbStep].ch2 = ch2;
374 comp->steps[comp->nbStep].op = op;
375 comp->steps[comp->nbStep].value = value;
376 comp->steps[comp->nbStep].value2 = value2;
377 comp->steps[comp->nbStep].value3 = value3;
378 comp->steps[comp->nbStep].value4 = value4;
379 comp->steps[comp->nbStep].value5 = value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000380 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000381 return(comp->nbStep++);
382}
383
Daniel Veillardf06307e2001-07-03 10:35:50 +0000384/**
385 * xmlXPathCompSwap:
386 * @comp: the compiled expression
387 * @op: operation index
388 *
389 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000390 */
391static void
392xmlXPathCompSwap(xmlXPathStepOpPtr op) {
393 int tmp;
394
Daniel Veillard81463942001-10-16 12:34:39 +0000395#ifdef LIBXML_THREADS_ENABLED
396 /*
397 * Since this manipulates possibly shared variables, this is
398 * disable if one detects that the library is used in a multithreaded
399 * application
400 */
401 if (xmlXPathDisableOptimizer)
402 return;
403#endif
404
Daniel Veillardf06307e2001-07-03 10:35:50 +0000405 tmp = op->ch1;
406 op->ch1 = op->ch2;
407 op->ch2 = tmp;
408}
409
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000410#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
411 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
412 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000413#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
414 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
415 (op), (val), (val2), (val3), (val4), (val5))
416
417#define PUSH_LEAVE_EXPR(op, val, val2) \
418xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
419
420#define PUSH_UNARY_EXPR(op, ch, val, val2) \
421xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
422
423#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
424xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), (val), (val2), 0 ,NULL ,NULL)
425
426/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000427 * *
428 * Debugging related functions *
429 * *
430 ************************************************************************/
431
432#define TODO \
433 xmlGenericError(xmlGenericErrorContext, \
434 "Unimplemented block at %s:%d\n", \
435 __FILE__, __LINE__);
436
437#define STRANGE \
438 xmlGenericError(xmlGenericErrorContext, \
439 "Internal error at %s:%d\n", \
440 __FILE__, __LINE__);
441
442#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000443static void
444xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000445 int i;
446 char shift[100];
447
448 for (i = 0;((i < depth) && (i < 25));i++)
449 shift[2 * i] = shift[2 * i + 1] = ' ';
450 shift[2 * i] = shift[2 * i + 1] = 0;
451 if (cur == NULL) {
452 fprintf(output, shift);
453 fprintf(output, "Node is NULL !\n");
454 return;
455
456 }
457
458 if ((cur->type == XML_DOCUMENT_NODE) ||
459 (cur->type == XML_HTML_DOCUMENT_NODE)) {
460 fprintf(output, shift);
461 fprintf(output, " /\n");
462 } else if (cur->type == XML_ATTRIBUTE_NODE)
463 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
464 else
465 xmlDebugDumpOneNode(output, cur, depth);
466}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000467static void
468xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000469 xmlNodePtr tmp;
470 int i;
471 char shift[100];
472
473 for (i = 0;((i < depth) && (i < 25));i++)
474 shift[2 * i] = shift[2 * i + 1] = ' ';
475 shift[2 * i] = shift[2 * i + 1] = 0;
476 if (cur == NULL) {
477 fprintf(output, shift);
478 fprintf(output, "Node is NULL !\n");
479 return;
480
481 }
482
483 while (cur != NULL) {
484 tmp = cur;
485 cur = cur->next;
486 xmlDebugDumpOneNode(output, tmp, depth);
487 }
488}
Owen Taylor3473f882001-02-23 17:55:21 +0000489
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000490static void
491xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000492 int i;
493 char shift[100];
494
495 for (i = 0;((i < depth) && (i < 25));i++)
496 shift[2 * i] = shift[2 * i + 1] = ' ';
497 shift[2 * i] = shift[2 * i + 1] = 0;
498
499 if (cur == NULL) {
500 fprintf(output, shift);
501 fprintf(output, "NodeSet is NULL !\n");
502 return;
503
504 }
505
Daniel Veillard911f49a2001-04-07 15:39:35 +0000506 if (cur != NULL) {
507 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
508 for (i = 0;i < cur->nodeNr;i++) {
509 fprintf(output, shift);
510 fprintf(output, "%d", i + 1);
511 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
512 }
Owen Taylor3473f882001-02-23 17:55:21 +0000513 }
514}
515
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000516static void
517xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000518 int i;
519 char shift[100];
520
521 for (i = 0;((i < depth) && (i < 25));i++)
522 shift[2 * i] = shift[2 * i + 1] = ' ';
523 shift[2 * i] = shift[2 * i + 1] = 0;
524
525 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
526 fprintf(output, shift);
527 fprintf(output, "Value Tree is NULL !\n");
528 return;
529
530 }
531
532 fprintf(output, shift);
533 fprintf(output, "%d", i + 1);
534 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
535}
Owen Taylor3473f882001-02-23 17:55:21 +0000536#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000537static void
538xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000539 int i;
540 char shift[100];
541
542 for (i = 0;((i < depth) && (i < 25));i++)
543 shift[2 * i] = shift[2 * i + 1] = ' ';
544 shift[2 * i] = shift[2 * i + 1] = 0;
545
546 if (cur == NULL) {
547 fprintf(output, shift);
548 fprintf(output, "LocationSet is NULL !\n");
549 return;
550
551 }
552
553 for (i = 0;i < cur->locNr;i++) {
554 fprintf(output, shift);
555 fprintf(output, "%d : ", i + 1);
556 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
557 }
558}
Daniel Veillard017b1082001-06-21 11:20:21 +0000559#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000560
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000561/**
562 * xmlXPathDebugDumpObject:
563 * @output: the FILE * to dump the output
564 * @cur: the object to inspect
565 * @depth: indentation level
566 *
567 * Dump the content of the object for debugging purposes
568 */
569void
570xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000571 int i;
572 char shift[100];
573
574 for (i = 0;((i < depth) && (i < 25));i++)
575 shift[2 * i] = shift[2 * i + 1] = ' ';
576 shift[2 * i] = shift[2 * i + 1] = 0;
577
578 fprintf(output, shift);
579
580 if (cur == NULL) {
581 fprintf(output, "Object is empty (NULL)\n");
582 return;
583 }
584 switch(cur->type) {
585 case XPATH_UNDEFINED:
586 fprintf(output, "Object is uninitialized\n");
587 break;
588 case XPATH_NODESET:
589 fprintf(output, "Object is a Node Set :\n");
590 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
591 break;
592 case XPATH_XSLT_TREE:
593 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000594 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000595 break;
596 case XPATH_BOOLEAN:
597 fprintf(output, "Object is a Boolean : ");
598 if (cur->boolval) fprintf(output, "true\n");
599 else fprintf(output, "false\n");
600 break;
601 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +0000602 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000603 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000604 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000605 break;
606 case -1:
607 fprintf(output, "Object is a number : -Infinity\n");
608 break;
609 default:
Daniel Veillardcda96922001-08-21 10:56:31 +0000610 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000611 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +0000612 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
613 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000614 } else {
615 fprintf(output, "Object is a number : %0g\n", cur->floatval);
616 }
617 }
Owen Taylor3473f882001-02-23 17:55:21 +0000618 break;
619 case XPATH_STRING:
620 fprintf(output, "Object is a string : ");
621 xmlDebugDumpString(output, cur->stringval);
622 fprintf(output, "\n");
623 break;
624 case XPATH_POINT:
625 fprintf(output, "Object is a point : index %d in node", cur->index);
626 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
627 fprintf(output, "\n");
628 break;
629 case XPATH_RANGE:
630 if ((cur->user2 == NULL) ||
631 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
632 fprintf(output, "Object is a collapsed range :\n");
633 fprintf(output, shift);
634 if (cur->index >= 0)
635 fprintf(output, "index %d in ", cur->index);
636 fprintf(output, "node\n");
637 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
638 depth + 1);
639 } else {
640 fprintf(output, "Object is a range :\n");
641 fprintf(output, shift);
642 fprintf(output, "From ");
643 if (cur->index >= 0)
644 fprintf(output, "index %d in ", cur->index);
645 fprintf(output, "node\n");
646 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
647 depth + 1);
648 fprintf(output, shift);
649 fprintf(output, "To ");
650 if (cur->index2 >= 0)
651 fprintf(output, "index %d in ", cur->index2);
652 fprintf(output, "node\n");
653 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
654 depth + 1);
655 fprintf(output, "\n");
656 }
657 break;
658 case XPATH_LOCATIONSET:
659#if defined(LIBXML_XPTR_ENABLED)
660 fprintf(output, "Object is a Location Set:\n");
661 xmlXPathDebugDumpLocationSet(output,
662 (xmlLocationSetPtr) cur->user, depth);
663#endif
664 break;
665 case XPATH_USERS:
666 fprintf(output, "Object is user defined\n");
667 break;
668 }
669}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000670
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000671static void
672xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000673 xmlXPathStepOpPtr op, int depth) {
674 int i;
675 char shift[100];
676
677 for (i = 0;((i < depth) && (i < 25));i++)
678 shift[2 * i] = shift[2 * i + 1] = ' ';
679 shift[2 * i] = shift[2 * i + 1] = 0;
680
681 fprintf(output, shift);
682 if (op == NULL) {
683 fprintf(output, "Step is NULL\n");
684 return;
685 }
686 switch (op->op) {
687 case XPATH_OP_END:
688 fprintf(output, "END"); break;
689 case XPATH_OP_AND:
690 fprintf(output, "AND"); break;
691 case XPATH_OP_OR:
692 fprintf(output, "OR"); break;
693 case XPATH_OP_EQUAL:
694 if (op->value)
695 fprintf(output, "EQUAL =");
696 else
697 fprintf(output, "EQUAL !=");
698 break;
699 case XPATH_OP_CMP:
700 if (op->value)
701 fprintf(output, "CMP <");
702 else
703 fprintf(output, "CMP >");
704 if (!op->value2)
705 fprintf(output, "=");
706 break;
707 case XPATH_OP_PLUS:
708 if (op->value == 0)
709 fprintf(output, "PLUS -");
710 else if (op->value == 1)
711 fprintf(output, "PLUS +");
712 else if (op->value == 2)
713 fprintf(output, "PLUS unary -");
714 else if (op->value == 3)
715 fprintf(output, "PLUS unary - -");
716 break;
717 case XPATH_OP_MULT:
718 if (op->value == 0)
719 fprintf(output, "MULT *");
720 else if (op->value == 1)
721 fprintf(output, "MULT div");
722 else
723 fprintf(output, "MULT mod");
724 break;
725 case XPATH_OP_UNION:
726 fprintf(output, "UNION"); break;
727 case XPATH_OP_ROOT:
728 fprintf(output, "ROOT"); break;
729 case XPATH_OP_NODE:
730 fprintf(output, "NODE"); break;
731 case XPATH_OP_RESET:
732 fprintf(output, "RESET"); break;
733 case XPATH_OP_SORT:
734 fprintf(output, "SORT"); break;
735 case XPATH_OP_COLLECT: {
736 xmlXPathAxisVal axis = op->value;
737 xmlXPathTestVal test = op->value2;
738 xmlXPathTypeVal type = op->value3;
739 const xmlChar *prefix = op->value4;
740 const xmlChar *name = op->value5;
741
742 fprintf(output, "COLLECT ");
743 switch (axis) {
744 case AXIS_ANCESTOR:
745 fprintf(output, " 'ancestors' "); break;
746 case AXIS_ANCESTOR_OR_SELF:
747 fprintf(output, " 'ancestors-or-self' "); break;
748 case AXIS_ATTRIBUTE:
749 fprintf(output, " 'attributes' "); break;
750 case AXIS_CHILD:
751 fprintf(output, " 'child' "); break;
752 case AXIS_DESCENDANT:
753 fprintf(output, " 'descendant' "); break;
754 case AXIS_DESCENDANT_OR_SELF:
755 fprintf(output, " 'descendant-or-self' "); break;
756 case AXIS_FOLLOWING:
757 fprintf(output, " 'following' "); break;
758 case AXIS_FOLLOWING_SIBLING:
759 fprintf(output, " 'following-siblings' "); break;
760 case AXIS_NAMESPACE:
761 fprintf(output, " 'namespace' "); break;
762 case AXIS_PARENT:
763 fprintf(output, " 'parent' "); break;
764 case AXIS_PRECEDING:
765 fprintf(output, " 'preceding' "); break;
766 case AXIS_PRECEDING_SIBLING:
767 fprintf(output, " 'preceding-sibling' "); break;
768 case AXIS_SELF:
769 fprintf(output, " 'self' "); break;
770 }
771 switch (test) {
772 case NODE_TEST_NONE:
773 fprintf(output, "'none' "); break;
774 case NODE_TEST_TYPE:
775 fprintf(output, "'type' "); break;
776 case NODE_TEST_PI:
777 fprintf(output, "'PI' "); break;
778 case NODE_TEST_ALL:
779 fprintf(output, "'all' "); break;
780 case NODE_TEST_NS:
781 fprintf(output, "'namespace' "); break;
782 case NODE_TEST_NAME:
783 fprintf(output, "'name' "); break;
784 }
785 switch (type) {
786 case NODE_TYPE_NODE:
787 fprintf(output, "'node' "); break;
788 case NODE_TYPE_COMMENT:
789 fprintf(output, "'comment' "); break;
790 case NODE_TYPE_TEXT:
791 fprintf(output, "'text' "); break;
792 case NODE_TYPE_PI:
793 fprintf(output, "'PI' "); break;
794 }
795 if (prefix != NULL)
796 fprintf(output, "%s:", prefix);
797 if (name != NULL)
798 fprintf(output, "%s", name);
799 break;
800
801 }
802 case XPATH_OP_VALUE: {
803 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
804
805 fprintf(output, "ELEM ");
806 xmlXPathDebugDumpObject(output, object, 0);
807 goto finish;
808 }
809 case XPATH_OP_VARIABLE: {
810 const xmlChar *prefix = op->value5;
811 const xmlChar *name = op->value4;
812
813 if (prefix != NULL)
814 fprintf(output, "VARIABLE %s:%s", prefix, name);
815 else
816 fprintf(output, "VARIABLE %s", name);
817 break;
818 }
819 case XPATH_OP_FUNCTION: {
820 int nbargs = op->value;
821 const xmlChar *prefix = op->value5;
822 const xmlChar *name = op->value4;
823
824 if (prefix != NULL)
825 fprintf(output, "FUNCTION %s:%s(%d args)",
826 prefix, name, nbargs);
827 else
828 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
829 break;
830 }
831 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
832 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000833 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +0000834#ifdef LIBXML_XPTR_ENABLED
835 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
836#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000837 default:
838 fprintf(output, "UNKNOWN %d\n", op->op); return;
839 }
840 fprintf(output, "\n");
841finish:
842 if (op->ch1 >= 0)
843 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
844 if (op->ch2 >= 0)
845 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
846}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000847
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000848/**
849 * xmlXPathDebugDumpCompExpr:
850 * @output: the FILE * for the output
851 * @comp: the precompiled XPath expression
852 * @depth: the indentation level.
853 *
854 * Dumps the tree of the compiled XPath expression.
855 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000856void
857xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
858 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000859 int i;
860 char shift[100];
861
862 for (i = 0;((i < depth) && (i < 25));i++)
863 shift[2 * i] = shift[2 * i + 1] = ' ';
864 shift[2 * i] = shift[2 * i + 1] = 0;
865
866 fprintf(output, shift);
867
868 if (comp == NULL) {
869 fprintf(output, "Compiled Expression is NULL\n");
870 return;
871 }
872 fprintf(output, "Compiled Expression : %d elements\n",
873 comp->nbStep);
874 i = comp->last;
875 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
876}
Daniel Veillard017b1082001-06-21 11:20:21 +0000877#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000878
879/************************************************************************
880 * *
881 * Parser stacks related functions and macros *
882 * *
883 ************************************************************************/
884
885/*
886 * Generic function for accessing stacks in the Parser Context
887 */
888
889#define PUSH_AND_POP(type, name) \
890extern int name##Push(xmlXPathParserContextPtr ctxt, type value) { \
891 if (ctxt->name##Nr >= ctxt->name##Max) { \
892 ctxt->name##Max *= 2; \
893 ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab, \
894 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
895 if (ctxt->name##Tab == NULL) { \
896 xmlGenericError(xmlGenericErrorContext, \
897 "realloc failed !\n"); \
898 return(0); \
899 } \
900 } \
901 ctxt->name##Tab[ctxt->name##Nr] = value; \
902 ctxt->name = value; \
903 return(ctxt->name##Nr++); \
904} \
905extern type name##Pop(xmlXPathParserContextPtr ctxt) { \
906 type ret; \
907 if (ctxt->name##Nr <= 0) return(0); \
908 ctxt->name##Nr--; \
909 if (ctxt->name##Nr > 0) \
910 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
911 else \
912 ctxt->name = NULL; \
913 ret = ctxt->name##Tab[ctxt->name##Nr]; \
914 ctxt->name##Tab[ctxt->name##Nr] = 0; \
915 return(ret); \
916} \
917
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000918/**
919 * valuePop:
920 * @ctxt: an XPath evaluation context
921 *
922 * Pops the top XPath object from the value stack
923 *
924 * Returns the XPath object just removed
925 */
926/**
927 * valuePush:
928 * @ctxt: an XPath evaluation context
929 * @value: the XPath object
930 *
931 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000932 *
933 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000934 */
Owen Taylor3473f882001-02-23 17:55:21 +0000935PUSH_AND_POP(xmlXPathObjectPtr, value)
936
Thomas Broyerf06a3d82001-07-16 04:52:57 +0000937/**
938 * xmlXPathPopBoolean:
939 * @ctxt: an XPath parser context
940 *
941 * Pops a boolean from the stack, handling conversion if needed.
942 * Check error with #xmlXPathCheckError.
943 *
944 * Returns the boolean
945 */
946int
947xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
948 xmlXPathObjectPtr obj;
949 int ret;
950
951 obj = valuePop(ctxt);
952 if (obj == NULL) {
953 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
954 return(0);
955 }
956 ret = xmlXPathCastToBoolean(obj);
957 xmlXPathFreeObject(obj);
958 return(ret);
959}
960
961/**
962 * xmlXPathPopNumber:
963 * @ctxt: an XPath parser context
964 *
965 * Pops a number from the stack, handling conversion if needed.
966 * Check error with #xmlXPathCheckError.
967 *
968 * Returns the number
969 */
970double
971xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
972 xmlXPathObjectPtr obj;
973 double ret;
974
975 obj = valuePop(ctxt);
976 if (obj == NULL) {
977 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
978 return(0);
979 }
980 ret = xmlXPathCastToNumber(obj);
981 xmlXPathFreeObject(obj);
982 return(ret);
983}
984
985/**
986 * xmlXPathPopString:
987 * @ctxt: an XPath parser context
988 *
989 * Pops a string from the stack, handling conversion if needed.
990 * Check error with #xmlXPathCheckError.
991 *
992 * Returns the string
993 */
994xmlChar *
995xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
996 xmlXPathObjectPtr obj;
997 xmlChar * ret;
998
999 obj = valuePop(ctxt);
1000 if (obj == NULL) {
1001 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1002 return(NULL);
1003 }
1004 ret = xmlXPathCastToString(obj);
1005 /* TODO: needs refactoring somewhere else */
1006 if (obj->stringval == ret)
1007 obj->stringval = NULL;
1008 xmlXPathFreeObject(obj);
1009 return(ret);
1010}
1011
1012/**
1013 * xmlXPathPopNodeSet:
1014 * @ctxt: an XPath parser context
1015 *
1016 * Pops a node-set from the stack, handling conversion if needed.
1017 * Check error with #xmlXPathCheckError.
1018 *
1019 * Returns the node-set
1020 */
1021xmlNodeSetPtr
1022xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
1023 xmlXPathObjectPtr obj;
1024 xmlNodeSetPtr ret;
1025
1026 if (ctxt->value == NULL) {
1027 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1028 return(NULL);
1029 }
1030 if (!xmlXPathStackIsNodeSet(ctxt)) {
1031 xmlXPathSetTypeError(ctxt);
1032 return(NULL);
1033 }
1034 obj = valuePop(ctxt);
1035 ret = obj->nodesetval;
1036 xmlXPathFreeNodeSetList(obj);
1037 return(ret);
1038}
1039
1040/**
1041 * xmlXPathPopExternal:
1042 * @ctxt: an XPath parser context
1043 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001044 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001045 * Check error with #xmlXPathCheckError.
1046 *
1047 * Returns the object
1048 */
1049void *
1050xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1051 xmlXPathObjectPtr obj;
1052 void * ret;
1053
1054 if (ctxt->value == NULL) {
1055 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1056 return(NULL);
1057 }
1058 if (ctxt->value->type != XPATH_USERS) {
1059 xmlXPathSetTypeError(ctxt);
1060 return(NULL);
1061 }
1062 obj = valuePop(ctxt);
1063 ret = obj->user;
1064 xmlXPathFreeObject(obj);
1065 return(ret);
1066}
1067
Owen Taylor3473f882001-02-23 17:55:21 +00001068/*
1069 * Macros for accessing the content. Those should be used only by the parser,
1070 * and not exported.
1071 *
1072 * Dirty macros, i.e. one need to make assumption on the context to use them
1073 *
1074 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1075 * CUR returns the current xmlChar value, i.e. a 8 bit value
1076 * in ISO-Latin or UTF-8.
1077 * This should be used internally by the parser
1078 * only to compare to ASCII values otherwise it would break when
1079 * running with UTF-8 encoding.
1080 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1081 * to compare on ASCII based substring.
1082 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1083 * strings within the parser.
1084 * CURRENT Returns the current char value, with the full decoding of
1085 * UTF-8 if we are using this mode. It returns an int.
1086 * NEXT Skip to the next character, this does the proper decoding
1087 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1088 * It returns the pointer to the current xmlChar.
1089 */
1090
1091#define CUR (*ctxt->cur)
1092#define SKIP(val) ctxt->cur += (val)
1093#define NXT(val) ctxt->cur[(val)]
1094#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001095#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1096
1097#define COPY_BUF(l,b,i,v) \
1098 if (l == 1) b[i++] = (xmlChar) v; \
1099 else i += xmlCopyChar(l,&b[i],v)
1100
1101#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001102
1103#define SKIP_BLANKS \
1104 while (IS_BLANK(*(ctxt->cur))) NEXT
1105
1106#define CURRENT (*ctxt->cur)
1107#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1108
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001109
1110#ifndef DBL_DIG
1111#define DBL_DIG 16
1112#endif
1113#ifndef DBL_EPSILON
1114#define DBL_EPSILON 1E-9
1115#endif
1116
1117#define UPPER_DOUBLE 1E9
1118#define LOWER_DOUBLE 1E-5
1119
1120#define INTEGER_DIGITS DBL_DIG
1121#define FRACTION_DIGITS (DBL_DIG + 1)
1122#define EXPONENT_DIGITS (3 + 2)
1123
1124/**
1125 * xmlXPathFormatNumber:
1126 * @number: number to format
1127 * @buffer: output buffer
1128 * @buffersize: size of output buffer
1129 *
1130 * Convert the number into a string representation.
1131 */
1132static void
1133xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1134{
Daniel Veillardcda96922001-08-21 10:56:31 +00001135 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001136 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001137 if (buffersize > (int)sizeof("Infinity"))
1138 sprintf(buffer, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001139 break;
1140 case -1:
1141 if (buffersize > (int)sizeof("-Infinity"))
1142 sprintf(buffer, "-Infinity");
1143 break;
1144 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001145 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001146 if (buffersize > (int)sizeof("NaN"))
1147 sprintf(buffer, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001148 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
1149 sprintf(buffer, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001150 } else if (number == ((int) number)) {
1151 char work[30];
1152 char *ptr, *cur;
1153 int res, value = (int) number;
1154
1155 ptr = &buffer[0];
1156 if (value < 0) {
1157 *ptr++ = '-';
1158 value = -value;
1159 }
1160 if (value == 0) {
1161 *ptr++ = '0';
1162 } else {
1163 cur = &work[0];
1164 while (value != 0) {
1165 res = value % 10;
1166 value = value / 10;
1167 *cur++ = '0' + res;
1168 }
1169 cur--;
1170 while ((cur >= &work[0]) && (ptr - buffer < buffersize)) {
1171 *ptr++ = *cur--;
1172 }
1173 }
1174 if (ptr - buffer < buffersize) {
1175 *ptr = 0;
1176 } else if (buffersize > 0) {
1177 ptr--;
1178 *ptr = 0;
1179 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001180 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001181 /* 3 is sign, decimal point, and terminating zero */
1182 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1183 int integer_place, fraction_place;
1184 char *ptr;
1185 char *after_fraction;
1186 double absolute_value;
1187 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001188
Bjorn Reese70a9da52001-04-21 16:57:29 +00001189 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001190
Bjorn Reese70a9da52001-04-21 16:57:29 +00001191 /*
1192 * First choose format - scientific or regular floating point.
1193 * In either case, result is in work, and after_fraction points
1194 * just past the fractional part.
1195 */
1196 if ( ((absolute_value > UPPER_DOUBLE) ||
1197 (absolute_value < LOWER_DOUBLE)) &&
1198 (absolute_value != 0.0) ) {
1199 /* Use scientific notation */
1200 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1201 fraction_place = DBL_DIG - 1;
1202 snprintf(work, sizeof(work),"%*.*e",
1203 integer_place, fraction_place, number);
1204 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001205 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001206 else {
1207 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001208 if (absolute_value > 0.0)
1209 integer_place = 1 + (int)log10(absolute_value);
1210 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001211 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001212 fraction_place = (integer_place > 0)
1213 ? DBL_DIG - integer_place
1214 : DBL_DIG;
1215 size = snprintf(work, sizeof(work), "%0.*f",
1216 fraction_place, number);
1217 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001218 }
1219
Bjorn Reese70a9da52001-04-21 16:57:29 +00001220 /* Remove fractional trailing zeroes */
1221 ptr = after_fraction;
1222 while (*(--ptr) == '0')
1223 ;
1224 if (*ptr != '.')
1225 ptr++;
1226 strcpy(ptr, after_fraction);
1227
1228 /* Finally copy result back to caller */
1229 size = strlen(work) + 1;
1230 if (size > buffersize) {
1231 work[buffersize - 1] = 0;
1232 size = buffersize;
1233 }
1234 memcpy(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001235 }
1236 break;
1237 }
1238}
1239
Owen Taylor3473f882001-02-23 17:55:21 +00001240/************************************************************************
1241 * *
1242 * Error handling routines *
1243 * *
1244 ************************************************************************/
1245
1246
Daniel Veillardb44025c2001-10-11 22:55:55 +00001247static const char *xmlXPathErrorMessages[] = {
Owen Taylor3473f882001-02-23 17:55:21 +00001248 "Ok",
1249 "Number encoding",
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001250 "Unfinished literal",
1251 "Start of literal",
Owen Taylor3473f882001-02-23 17:55:21 +00001252 "Expected $ for variable reference",
1253 "Undefined variable",
1254 "Invalid predicate",
1255 "Invalid expression",
1256 "Missing closing curly brace",
1257 "Unregistered function",
1258 "Invalid operand",
1259 "Invalid type",
1260 "Invalid number of arguments",
1261 "Invalid context size",
1262 "Invalid context position",
1263 "Memory allocation error",
1264 "Syntax error",
1265 "Resource error",
1266 "Sub resource error",
Daniel Veillard61d80a22001-04-27 17:13:01 +00001267 "Undefined namespace prefix",
1268 "Encoding error",
1269 "Char out of XML range"
Owen Taylor3473f882001-02-23 17:55:21 +00001270};
1271
1272/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001273 * xmlXPatherror:
Owen Taylor3473f882001-02-23 17:55:21 +00001274 * @ctxt: the XPath Parser context
1275 * @file: the file name
1276 * @line: the line number
1277 * @no: the error number
1278 *
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001279 * Formats an error message.
Owen Taylor3473f882001-02-23 17:55:21 +00001280 */
1281void
Daniel Veillard21458c82002-03-27 16:12:22 +00001282xmlXPatherror(xmlXPathParserContextPtr ctxt, ATTRIBUTE_UNUSED const char *file,
1283 ATTRIBUTE_UNUSED int line, int no) {
Owen Taylor3473f882001-02-23 17:55:21 +00001284 int n;
1285 const xmlChar *cur;
1286 const xmlChar *base;
1287
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001288/* xmlGenericError(xmlGenericErrorContext,
Owen Taylor3473f882001-02-23 17:55:21 +00001289 "Error %s:%d: %s\n", file, line,
1290 xmlXPathErrorMessages[no]);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001291*/
1292 xmlGenericError(xmlGenericErrorContext,
1293 "Error %s\n", xmlXPathErrorMessages[no]);
Owen Taylor3473f882001-02-23 17:55:21 +00001294
1295 cur = ctxt->cur;
1296 base = ctxt->base;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001297 if ((cur == NULL) || (base == NULL))
1298 return;
1299
Owen Taylor3473f882001-02-23 17:55:21 +00001300 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
1301 cur--;
1302 }
1303 n = 0;
1304 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
1305 cur--;
1306 if ((*cur == '\n') || (*cur == '\r')) cur++;
1307 base = cur;
1308 n = 0;
1309 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
1310 xmlGenericError(xmlGenericErrorContext, "%c", (unsigned char) *cur++);
1311 n++;
1312 }
1313 xmlGenericError(xmlGenericErrorContext, "\n");
1314 cur = ctxt->cur;
1315 while ((*cur == '\n') || (*cur == '\r'))
1316 cur--;
1317 n = 0;
1318 while ((cur != base) && (n++ < 80)) {
1319 xmlGenericError(xmlGenericErrorContext, " ");
1320 base++;
1321 }
1322 xmlGenericError(xmlGenericErrorContext,"^\n");
1323}
1324
1325
1326/************************************************************************
1327 * *
1328 * Routines to handle NodeSets *
1329 * *
1330 ************************************************************************/
1331
1332/**
1333 * xmlXPathCmpNodes:
1334 * @node1: the first node
1335 * @node2: the second node
1336 *
1337 * Compare two nodes w.r.t document order
1338 *
1339 * Returns -2 in case of error 1 if first point < second point, 0 if
1340 * that's the same node, -1 otherwise
1341 */
1342int
1343xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1344 int depth1, depth2;
1345 xmlNodePtr cur, root;
1346
1347 if ((node1 == NULL) || (node2 == NULL))
1348 return(-2);
1349 /*
1350 * a couple of optimizations which will avoid computations in most cases
1351 */
1352 if (node1 == node2)
1353 return(0);
Daniel Veillardb33c2012001-04-25 12:59:04 +00001354 if ((node1->type == XML_NAMESPACE_DECL) ||
1355 (node2->type == XML_NAMESPACE_DECL))
1356 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001357 if (node1 == node2->prev)
1358 return(1);
1359 if (node1 == node2->next)
1360 return(-1);
1361
1362 /*
1363 * compute depth to root
1364 */
1365 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1366 if (cur == node1)
1367 return(1);
1368 depth2++;
1369 }
1370 root = cur;
1371 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1372 if (cur == node2)
1373 return(-1);
1374 depth1++;
1375 }
1376 /*
1377 * Distinct document (or distinct entities :-( ) case.
1378 */
1379 if (root != cur) {
1380 return(-2);
1381 }
1382 /*
1383 * get the nearest common ancestor.
1384 */
1385 while (depth1 > depth2) {
1386 depth1--;
1387 node1 = node1->parent;
1388 }
1389 while (depth2 > depth1) {
1390 depth2--;
1391 node2 = node2->parent;
1392 }
1393 while (node1->parent != node2->parent) {
1394 node1 = node1->parent;
1395 node2 = node2->parent;
1396 /* should not happen but just in case ... */
1397 if ((node1 == NULL) || (node2 == NULL))
1398 return(-2);
1399 }
1400 /*
1401 * Find who's first.
1402 */
1403 if (node1 == node2->next)
1404 return(-1);
1405 for (cur = node1->next;cur != NULL;cur = cur->next)
1406 if (cur == node2)
1407 return(1);
1408 return(-1); /* assume there is no sibling list corruption */
1409}
1410
1411/**
1412 * xmlXPathNodeSetSort:
1413 * @set: the node set
1414 *
1415 * Sort the node set in document order
1416 */
1417void
1418xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001419 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001420 xmlNodePtr tmp;
1421
1422 if (set == NULL)
1423 return;
1424
1425 /* Use Shell's sort to sort the node-set */
1426 len = set->nodeNr;
1427 for (incr = len / 2; incr > 0; incr /= 2) {
1428 for (i = incr; i < len; i++) {
1429 j = i - incr;
1430 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001431 if (xmlXPathCmpNodes(set->nodeTab[j],
1432 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001433 tmp = set->nodeTab[j];
1434 set->nodeTab[j] = set->nodeTab[j + incr];
1435 set->nodeTab[j + incr] = tmp;
1436 j -= incr;
1437 } else
1438 break;
1439 }
1440 }
1441 }
1442}
1443
1444#define XML_NODESET_DEFAULT 10
1445/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001446 * xmlXPathNodeSetDupNs:
1447 * @node: the parent node of the namespace XPath node
1448 * @ns: the libxml namespace declaration node.
1449 *
1450 * Namespace node in libxml don't match the XPath semantic. In a node set
1451 * the namespace nodes are duplicated and the next pointer is set to the
1452 * parent node in the XPath semantic.
1453 *
1454 * Returns the newly created object.
1455 */
1456static xmlNodePtr
1457xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
1458 xmlNsPtr cur;
1459
1460 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1461 return(NULL);
1462 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
1463 return((xmlNodePtr) ns);
1464
1465 /*
1466 * Allocate a new Namespace and fill the fields.
1467 */
1468 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1469 if (cur == NULL) {
1470 xmlGenericError(xmlGenericErrorContext,
1471 "xmlXPathNodeSetDupNs : malloc failed\n");
1472 return(NULL);
1473 }
1474 memset(cur, 0, sizeof(xmlNs));
1475 cur->type = XML_NAMESPACE_DECL;
1476 if (ns->href != NULL)
1477 cur->href = xmlStrdup(ns->href);
1478 if (ns->prefix != NULL)
1479 cur->prefix = xmlStrdup(ns->prefix);
1480 cur->next = (xmlNsPtr) node;
1481 return((xmlNodePtr) cur);
1482}
1483
1484/**
1485 * xmlXPathNodeSetFreeNs:
1486 * @ns: the XPath namespace node found in a nodeset.
1487 *
1488 * Namespace node in libxml don't match the XPath semantic. In a node set
1489 * the namespace nodes are duplicated and the next pointer is set to the
1490 * parent node in the XPath semantic. Check if such a node need to be freed
1491 */
1492static void
1493xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
1494 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1495 return;
1496
1497 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
1498 if (ns->href != NULL)
1499 xmlFree((xmlChar *)ns->href);
1500 if (ns->prefix != NULL)
1501 xmlFree((xmlChar *)ns->prefix);
1502 xmlFree(ns);
1503 }
1504}
1505
1506/**
Owen Taylor3473f882001-02-23 17:55:21 +00001507 * xmlXPathNodeSetCreate:
1508 * @val: an initial xmlNodePtr, or NULL
1509 *
1510 * Create a new xmlNodeSetPtr of type double and of value @val
1511 *
1512 * Returns the newly created object.
1513 */
1514xmlNodeSetPtr
1515xmlXPathNodeSetCreate(xmlNodePtr val) {
1516 xmlNodeSetPtr ret;
1517
1518 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1519 if (ret == NULL) {
1520 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001521 "xmlXPathNodeSetCreate: out of memory\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001522 return(NULL);
1523 }
1524 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1525 if (val != NULL) {
1526 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1527 sizeof(xmlNodePtr));
1528 if (ret->nodeTab == NULL) {
1529 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001530 "xmlXPathNodeSetCreate: out of memory\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001531 return(NULL);
1532 }
1533 memset(ret->nodeTab, 0 ,
1534 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1535 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001536 if (val->type == XML_NAMESPACE_DECL) {
1537 xmlNsPtr ns = (xmlNsPtr) val;
1538
1539 ret->nodeTab[ret->nodeNr++] =
1540 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1541 } else
1542 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001543 }
1544 return(ret);
1545}
1546
1547/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001548 * xmlXPathNodeSetContains:
1549 * @cur: the node-set
1550 * @val: the node
1551 *
1552 * checks whether @cur contains @val
1553 *
1554 * Returns true (1) if @cur contains @val, false (0) otherwise
1555 */
1556int
1557xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1558 int i;
1559
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001560 if (val->type == XML_NAMESPACE_DECL) {
1561 for (i = 0; i < cur->nodeNr; i++) {
1562 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1563 xmlNsPtr ns1, ns2;
1564
1565 ns1 = (xmlNsPtr) val;
1566 ns2 = (xmlNsPtr) cur->nodeTab[i];
1567 if (ns1 == ns2)
1568 return(1);
1569 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
1570 (xmlStrEqual(ns1->prefix, ns2->prefix)))
1571 return(1);
1572 }
1573 }
1574 } else {
1575 for (i = 0; i < cur->nodeNr; i++) {
1576 if (cur->nodeTab[i] == val)
1577 return(1);
1578 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001579 }
1580 return(0);
1581}
1582
1583/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001584 * xmlXPathNodeSetAddNs:
1585 * @cur: the initial node set
1586 * @node: the hosting node
1587 * @ns: a the namespace node
1588 *
1589 * add a new namespace node to an existing NodeSet
1590 */
1591static void
1592xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
1593 int i;
1594
1595 if ((ns == NULL) || (node == NULL) || (ns->type != XML_NAMESPACE_DECL) ||
1596 (node->type != XML_ELEMENT_NODE))
1597 return;
1598
1599 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1600 /*
1601 * check against doublons
1602 */
1603 for (i = 0;i < cur->nodeNr;i++) {
1604 if ((cur->nodeTab[i] != NULL) &&
1605 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00001606 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001607 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
1608 return;
1609 }
1610
1611 /*
1612 * grow the nodeTab if needed
1613 */
1614 if (cur->nodeMax == 0) {
1615 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1616 sizeof(xmlNodePtr));
1617 if (cur->nodeTab == NULL) {
1618 xmlGenericError(xmlGenericErrorContext,
1619 "xmlXPathNodeSetAdd: out of memory\n");
1620 return;
1621 }
1622 memset(cur->nodeTab, 0 ,
1623 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1624 cur->nodeMax = XML_NODESET_DEFAULT;
1625 } else if (cur->nodeNr == cur->nodeMax) {
1626 xmlNodePtr *temp;
1627
1628 cur->nodeMax *= 2;
1629 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1630 sizeof(xmlNodePtr));
1631 if (temp == NULL) {
1632 xmlGenericError(xmlGenericErrorContext,
1633 "xmlXPathNodeSetAdd: out of memory\n");
1634 return;
1635 }
1636 cur->nodeTab = temp;
1637 }
1638 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
1639}
1640
1641/**
Owen Taylor3473f882001-02-23 17:55:21 +00001642 * xmlXPathNodeSetAdd:
1643 * @cur: the initial node set
1644 * @val: a new xmlNodePtr
1645 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001646 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00001647 */
1648void
1649xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1650 int i;
1651
1652 if (val == NULL) return;
1653
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001654 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001655 /*
1656 * check against doublons
1657 */
1658 for (i = 0;i < cur->nodeNr;i++)
1659 if (cur->nodeTab[i] == val) return;
1660
1661 /*
1662 * grow the nodeTab if needed
1663 */
1664 if (cur->nodeMax == 0) {
1665 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1666 sizeof(xmlNodePtr));
1667 if (cur->nodeTab == NULL) {
1668 xmlGenericError(xmlGenericErrorContext,
1669 "xmlXPathNodeSetAdd: out of memory\n");
1670 return;
1671 }
1672 memset(cur->nodeTab, 0 ,
1673 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1674 cur->nodeMax = XML_NODESET_DEFAULT;
1675 } else if (cur->nodeNr == cur->nodeMax) {
1676 xmlNodePtr *temp;
1677
1678 cur->nodeMax *= 2;
1679 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1680 sizeof(xmlNodePtr));
1681 if (temp == NULL) {
1682 xmlGenericError(xmlGenericErrorContext,
1683 "xmlXPathNodeSetAdd: out of memory\n");
1684 return;
1685 }
1686 cur->nodeTab = temp;
1687 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001688 if (val->type == XML_NAMESPACE_DECL) {
1689 xmlNsPtr ns = (xmlNsPtr) val;
1690
1691 cur->nodeTab[cur->nodeNr++] =
1692 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1693 } else
1694 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001695}
1696
1697/**
1698 * xmlXPathNodeSetAddUnique:
1699 * @cur: the initial node set
1700 * @val: a new xmlNodePtr
1701 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001702 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00001703 * when we are sure the node is not already in the set.
1704 */
1705void
1706xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1707 if (val == NULL) return;
1708
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001709 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001710 /*
1711 * grow the nodeTab if needed
1712 */
1713 if (cur->nodeMax == 0) {
1714 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1715 sizeof(xmlNodePtr));
1716 if (cur->nodeTab == NULL) {
1717 xmlGenericError(xmlGenericErrorContext,
1718 "xmlXPathNodeSetAddUnique: out of memory\n");
1719 return;
1720 }
1721 memset(cur->nodeTab, 0 ,
1722 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1723 cur->nodeMax = XML_NODESET_DEFAULT;
1724 } else if (cur->nodeNr == cur->nodeMax) {
1725 xmlNodePtr *temp;
1726
1727 cur->nodeMax *= 2;
1728 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1729 sizeof(xmlNodePtr));
1730 if (temp == NULL) {
1731 xmlGenericError(xmlGenericErrorContext,
1732 "xmlXPathNodeSetAddUnique: out of memory\n");
1733 return;
1734 }
1735 cur->nodeTab = temp;
1736 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001737 if (val->type == XML_NAMESPACE_DECL) {
1738 xmlNsPtr ns = (xmlNsPtr) val;
1739
1740 cur->nodeTab[cur->nodeNr++] =
1741 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1742 } else
1743 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001744}
1745
1746/**
1747 * xmlXPathNodeSetMerge:
1748 * @val1: the first NodeSet or NULL
1749 * @val2: the second NodeSet
1750 *
1751 * Merges two nodesets, all nodes from @val2 are added to @val1
1752 * if @val1 is NULL, a new set is created and copied from @val2
1753 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001754 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00001755 */
1756xmlNodeSetPtr
1757xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001758 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001759
1760 if (val2 == NULL) return(val1);
1761 if (val1 == NULL) {
1762 val1 = xmlXPathNodeSetCreate(NULL);
1763 }
1764
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001765 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001766 initNr = val1->nodeNr;
1767
1768 for (i = 0;i < val2->nodeNr;i++) {
1769 /*
1770 * check against doublons
1771 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001772 skip = 0;
1773 for (j = 0; j < initNr; j++) {
1774 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1775 skip = 1;
1776 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001777 } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) &&
1778 (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) {
1779 xmlNsPtr ns1, ns2;
1780 ns1 = (xmlNsPtr) val1->nodeTab[j];
1781 ns2 = (xmlNsPtr) val2->nodeTab[i];
1782 if ((ns1->next == ns2->next) &&
1783 (xmlStrEqual(ns1->prefix, ns2->prefix))) {
1784 skip = 1;
1785 break;
1786 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001787 }
1788 }
1789 if (skip)
1790 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00001791
1792 /*
1793 * grow the nodeTab if needed
1794 */
1795 if (val1->nodeMax == 0) {
1796 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1797 sizeof(xmlNodePtr));
1798 if (val1->nodeTab == NULL) {
1799 xmlGenericError(xmlGenericErrorContext,
1800 "xmlXPathNodeSetMerge: out of memory\n");
1801 return(NULL);
1802 }
1803 memset(val1->nodeTab, 0 ,
1804 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1805 val1->nodeMax = XML_NODESET_DEFAULT;
1806 } else if (val1->nodeNr == val1->nodeMax) {
1807 xmlNodePtr *temp;
1808
1809 val1->nodeMax *= 2;
1810 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1811 sizeof(xmlNodePtr));
1812 if (temp == NULL) {
1813 xmlGenericError(xmlGenericErrorContext,
1814 "xmlXPathNodeSetMerge: out of memory\n");
1815 return(NULL);
1816 }
1817 val1->nodeTab = temp;
1818 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001819 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1820 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1821
1822 val1->nodeTab[val1->nodeNr++] =
1823 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1824 } else
1825 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00001826 }
1827
1828 return(val1);
1829}
1830
1831/**
Daniel Veillard75be0132002-03-13 10:03:35 +00001832 * xmlXPathNodeSetMergeUnique:
1833 * @val1: the first NodeSet or NULL
1834 * @val2: the second NodeSet
1835 *
1836 * Merges two nodesets, all nodes from @val2 are added to @val1
1837 * if @val1 is NULL, a new set is created and copied from @val2
1838 *
1839 * Returns @val1 once extended or NULL in case of error.
1840 */
1841static xmlNodeSetPtr
1842xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
1843 int i, initNr;
1844
1845 if (val2 == NULL) return(val1);
1846 if (val1 == NULL) {
1847 val1 = xmlXPathNodeSetCreate(NULL);
1848 }
1849
1850 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1851 initNr = val1->nodeNr;
1852
1853 for (i = 0;i < val2->nodeNr;i++) {
1854 /*
1855 * grow the nodeTab if needed
1856 */
1857 if (val1->nodeMax == 0) {
1858 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1859 sizeof(xmlNodePtr));
1860 if (val1->nodeTab == NULL) {
1861 xmlGenericError(xmlGenericErrorContext,
1862 "xmlXPathNodeSetMerge: out of memory\n");
1863 return(NULL);
1864 }
1865 memset(val1->nodeTab, 0 ,
1866 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1867 val1->nodeMax = XML_NODESET_DEFAULT;
1868 } else if (val1->nodeNr == val1->nodeMax) {
1869 xmlNodePtr *temp;
1870
1871 val1->nodeMax *= 2;
1872 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1873 sizeof(xmlNodePtr));
1874 if (temp == NULL) {
1875 xmlGenericError(xmlGenericErrorContext,
1876 "xmlXPathNodeSetMerge: out of memory\n");
1877 return(NULL);
1878 }
1879 val1->nodeTab = temp;
1880 }
1881 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1882 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1883
1884 val1->nodeTab[val1->nodeNr++] =
1885 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1886 } else
1887 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
1888 }
1889
1890 return(val1);
1891}
1892
1893/**
Owen Taylor3473f882001-02-23 17:55:21 +00001894 * xmlXPathNodeSetDel:
1895 * @cur: the initial node set
1896 * @val: an xmlNodePtr
1897 *
1898 * Removes an xmlNodePtr from an existing NodeSet
1899 */
1900void
1901xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
1902 int i;
1903
1904 if (cur == NULL) return;
1905 if (val == NULL) return;
1906
1907 /*
1908 * check against doublons
1909 */
1910 for (i = 0;i < cur->nodeNr;i++)
1911 if (cur->nodeTab[i] == val) break;
1912
1913 if (i >= cur->nodeNr) {
1914#ifdef DEBUG
1915 xmlGenericError(xmlGenericErrorContext,
1916 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
1917 val->name);
1918#endif
1919 return;
1920 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001921 if ((cur->nodeTab[i] != NULL) &&
1922 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
1923 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001924 cur->nodeNr--;
1925 for (;i < cur->nodeNr;i++)
1926 cur->nodeTab[i] = cur->nodeTab[i + 1];
1927 cur->nodeTab[cur->nodeNr] = NULL;
1928}
1929
1930/**
1931 * xmlXPathNodeSetRemove:
1932 * @cur: the initial node set
1933 * @val: the index to remove
1934 *
1935 * Removes an entry from an existing NodeSet list.
1936 */
1937void
1938xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
1939 if (cur == NULL) return;
1940 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001941 if ((cur->nodeTab[val] != NULL) &&
1942 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
1943 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00001944 cur->nodeNr--;
1945 for (;val < cur->nodeNr;val++)
1946 cur->nodeTab[val] = cur->nodeTab[val + 1];
1947 cur->nodeTab[cur->nodeNr] = NULL;
1948}
1949
1950/**
1951 * xmlXPathFreeNodeSet:
1952 * @obj: the xmlNodeSetPtr to free
1953 *
1954 * Free the NodeSet compound (not the actual nodes !).
1955 */
1956void
1957xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
1958 if (obj == NULL) return;
1959 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001960 int i;
1961
1962 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1963 for (i = 0;i < obj->nodeNr;i++)
1964 if ((obj->nodeTab[i] != NULL) &&
1965 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
1966 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001967 xmlFree(obj->nodeTab);
1968 }
Owen Taylor3473f882001-02-23 17:55:21 +00001969 xmlFree(obj);
1970}
1971
1972/**
1973 * xmlXPathFreeValueTree:
1974 * @obj: the xmlNodeSetPtr to free
1975 *
1976 * Free the NodeSet compound and the actual tree, this is different
1977 * from xmlXPathFreeNodeSet()
1978 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001979static void
Owen Taylor3473f882001-02-23 17:55:21 +00001980xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
1981 int i;
1982
1983 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001984
1985 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001986 for (i = 0;i < obj->nodeNr;i++) {
1987 if (obj->nodeTab[i] != NULL) {
1988 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1989 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
1990 } else {
1991 xmlFreeNodeList(obj->nodeTab[i]);
1992 }
1993 }
1994 }
Owen Taylor3473f882001-02-23 17:55:21 +00001995 xmlFree(obj->nodeTab);
1996 }
Owen Taylor3473f882001-02-23 17:55:21 +00001997 xmlFree(obj);
1998}
1999
2000#if defined(DEBUG) || defined(DEBUG_STEP)
2001/**
2002 * xmlGenericErrorContextNodeSet:
2003 * @output: a FILE * for the output
2004 * @obj: the xmlNodeSetPtr to free
2005 *
2006 * Quick display of a NodeSet
2007 */
2008void
2009xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
2010 int i;
2011
2012 if (output == NULL) output = xmlGenericErrorContext;
2013 if (obj == NULL) {
2014 fprintf(output, "NodeSet == NULL !\n");
2015 return;
2016 }
2017 if (obj->nodeNr == 0) {
2018 fprintf(output, "NodeSet is empty\n");
2019 return;
2020 }
2021 if (obj->nodeTab == NULL) {
2022 fprintf(output, " nodeTab == NULL !\n");
2023 return;
2024 }
2025 for (i = 0; i < obj->nodeNr; i++) {
2026 if (obj->nodeTab[i] == NULL) {
2027 fprintf(output, " NULL !\n");
2028 return;
2029 }
2030 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
2031 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
2032 fprintf(output, " /");
2033 else if (obj->nodeTab[i]->name == NULL)
2034 fprintf(output, " noname!");
2035 else fprintf(output, " %s", obj->nodeTab[i]->name);
2036 }
2037 fprintf(output, "\n");
2038}
2039#endif
2040
2041/**
2042 * xmlXPathNewNodeSet:
2043 * @val: the NodePtr value
2044 *
2045 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2046 * it with the single Node @val
2047 *
2048 * Returns the newly created object.
2049 */
2050xmlXPathObjectPtr
2051xmlXPathNewNodeSet(xmlNodePtr val) {
2052 xmlXPathObjectPtr ret;
2053
2054 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2055 if (ret == NULL) {
2056 xmlGenericError(xmlGenericErrorContext,
2057 "xmlXPathNewNodeSet: out of memory\n");
2058 return(NULL);
2059 }
2060 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2061 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00002062 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002063 ret->nodesetval = xmlXPathNodeSetCreate(val);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002064 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002065 return(ret);
2066}
2067
2068/**
2069 * xmlXPathNewValueTree:
2070 * @val: the NodePtr value
2071 *
2072 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
2073 * it with the tree root @val
2074 *
2075 * Returns the newly created object.
2076 */
2077xmlXPathObjectPtr
2078xmlXPathNewValueTree(xmlNodePtr val) {
2079 xmlXPathObjectPtr ret;
2080
2081 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2082 if (ret == NULL) {
2083 xmlGenericError(xmlGenericErrorContext,
2084 "xmlXPathNewNodeSet: out of memory\n");
2085 return(NULL);
2086 }
2087 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2088 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002089 ret->boolval = 1;
2090 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00002091 ret->nodesetval = xmlXPathNodeSetCreate(val);
2092 return(ret);
2093}
2094
2095/**
2096 * xmlXPathNewNodeSetList:
2097 * @val: an existing NodeSet
2098 *
2099 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2100 * it with the Nodeset @val
2101 *
2102 * Returns the newly created object.
2103 */
2104xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002105xmlXPathNewNodeSetList(xmlNodeSetPtr val)
2106{
Owen Taylor3473f882001-02-23 17:55:21 +00002107 xmlXPathObjectPtr ret;
2108 int i;
2109
2110 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002111 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002112 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002113 ret = xmlXPathNewNodeSet(NULL);
2114 else {
2115 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
2116 for (i = 1; i < val->nodeNr; ++i)
2117 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2118 }
Owen Taylor3473f882001-02-23 17:55:21 +00002119
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002120 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002121}
2122
2123/**
2124 * xmlXPathWrapNodeSet:
2125 * @val: the NodePtr value
2126 *
2127 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2128 *
2129 * Returns the newly created object.
2130 */
2131xmlXPathObjectPtr
2132xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2133 xmlXPathObjectPtr ret;
2134
2135 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2136 if (ret == NULL) {
2137 xmlGenericError(xmlGenericErrorContext,
2138 "xmlXPathWrapNodeSet: out of memory\n");
2139 return(NULL);
2140 }
2141 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2142 ret->type = XPATH_NODESET;
2143 ret->nodesetval = val;
2144 return(ret);
2145}
2146
2147/**
2148 * xmlXPathFreeNodeSetList:
2149 * @obj: an existing NodeSetList object
2150 *
2151 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2152 * the list contrary to xmlXPathFreeObject().
2153 */
2154void
2155xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2156 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002157 xmlFree(obj);
2158}
2159
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002160/**
2161 * xmlXPathDifference:
2162 * @nodes1: a node-set
2163 * @nodes2: a node-set
2164 *
2165 * Implements the EXSLT - Sets difference() function:
2166 * node-set set:difference (node-set, node-set)
2167 *
2168 * Returns the difference between the two node sets, or nodes1 if
2169 * nodes2 is empty
2170 */
2171xmlNodeSetPtr
2172xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2173 xmlNodeSetPtr ret;
2174 int i, l1;
2175 xmlNodePtr cur;
2176
2177 if (xmlXPathNodeSetIsEmpty(nodes2))
2178 return(nodes1);
2179
2180 ret = xmlXPathNodeSetCreate(NULL);
2181 if (xmlXPathNodeSetIsEmpty(nodes1))
2182 return(ret);
2183
2184 l1 = xmlXPathNodeSetGetLength(nodes1);
2185
2186 for (i = 0; i < l1; i++) {
2187 cur = xmlXPathNodeSetItem(nodes1, i);
2188 if (!xmlXPathNodeSetContains(nodes2, cur))
2189 xmlXPathNodeSetAddUnique(ret, cur);
2190 }
2191 return(ret);
2192}
2193
2194/**
2195 * xmlXPathIntersection:
2196 * @nodes1: a node-set
2197 * @nodes2: a node-set
2198 *
2199 * Implements the EXSLT - Sets intersection() function:
2200 * node-set set:intersection (node-set, node-set)
2201 *
2202 * Returns a node set comprising the nodes that are within both the
2203 * node sets passed as arguments
2204 */
2205xmlNodeSetPtr
2206xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2207 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2208 int i, l1;
2209 xmlNodePtr cur;
2210
2211 if (xmlXPathNodeSetIsEmpty(nodes1))
2212 return(ret);
2213 if (xmlXPathNodeSetIsEmpty(nodes2))
2214 return(ret);
2215
2216 l1 = xmlXPathNodeSetGetLength(nodes1);
2217
2218 for (i = 0; i < l1; i++) {
2219 cur = xmlXPathNodeSetItem(nodes1, i);
2220 if (xmlXPathNodeSetContains(nodes2, cur))
2221 xmlXPathNodeSetAddUnique(ret, cur);
2222 }
2223 return(ret);
2224}
2225
2226/**
2227 * xmlXPathDistinctSorted:
2228 * @nodes: a node-set, sorted by document order
2229 *
2230 * Implements the EXSLT - Sets distinct() function:
2231 * node-set set:distinct (node-set)
2232 *
2233 * Returns a subset of the nodes contained in @nodes, or @nodes if
2234 * it is empty
2235 */
2236xmlNodeSetPtr
2237xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2238 xmlNodeSetPtr ret;
2239 xmlHashTablePtr hash;
2240 int i, l;
2241 xmlChar * strval;
2242 xmlNodePtr cur;
2243
2244 if (xmlXPathNodeSetIsEmpty(nodes))
2245 return(nodes);
2246
2247 ret = xmlXPathNodeSetCreate(NULL);
2248 l = xmlXPathNodeSetGetLength(nodes);
2249 hash = xmlHashCreate (l);
2250 for (i = 0; i < l; i++) {
2251 cur = xmlXPathNodeSetItem(nodes, i);
2252 strval = xmlXPathCastNodeToString(cur);
2253 if (xmlHashLookup(hash, strval) == NULL) {
2254 xmlHashAddEntry(hash, strval, strval);
2255 xmlXPathNodeSetAddUnique(ret, cur);
2256 } else {
2257 xmlFree(strval);
2258 }
2259 }
2260 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2261 return(ret);
2262}
2263
2264/**
2265 * xmlXPathDistinct:
2266 * @nodes: a node-set
2267 *
2268 * Implements the EXSLT - Sets distinct() function:
2269 * node-set set:distinct (node-set)
2270 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2271 * is called with the sorted node-set
2272 *
2273 * Returns a subset of the nodes contained in @nodes, or @nodes if
2274 * it is empty
2275 */
2276xmlNodeSetPtr
2277xmlXPathDistinct (xmlNodeSetPtr nodes) {
2278 if (xmlXPathNodeSetIsEmpty(nodes))
2279 return(nodes);
2280
2281 xmlXPathNodeSetSort(nodes);
2282 return(xmlXPathDistinctSorted(nodes));
2283}
2284
2285/**
2286 * xmlXPathHasSameNodes:
2287 * @nodes1: a node-set
2288 * @nodes2: a node-set
2289 *
2290 * Implements the EXSLT - Sets has-same-nodes function:
2291 * boolean set:has-same-node(node-set, node-set)
2292 *
2293 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2294 * otherwise
2295 */
2296int
2297xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2298 int i, l;
2299 xmlNodePtr cur;
2300
2301 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2302 xmlXPathNodeSetIsEmpty(nodes2))
2303 return(0);
2304
2305 l = xmlXPathNodeSetGetLength(nodes1);
2306 for (i = 0; i < l; i++) {
2307 cur = xmlXPathNodeSetItem(nodes1, i);
2308 if (xmlXPathNodeSetContains(nodes2, cur))
2309 return(1);
2310 }
2311 return(0);
2312}
2313
2314/**
2315 * xmlXPathNodeLeadingSorted:
2316 * @nodes: a node-set, sorted by document order
2317 * @node: a node
2318 *
2319 * Implements the EXSLT - Sets leading() function:
2320 * node-set set:leading (node-set, node-set)
2321 *
2322 * Returns the nodes in @nodes that precede @node in document order,
2323 * @nodes if @node is NULL or an empty node-set if @nodes
2324 * doesn't contain @node
2325 */
2326xmlNodeSetPtr
2327xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2328 int i, l;
2329 xmlNodePtr cur;
2330 xmlNodeSetPtr ret;
2331
2332 if (node == NULL)
2333 return(nodes);
2334
2335 ret = xmlXPathNodeSetCreate(NULL);
2336 if (xmlXPathNodeSetIsEmpty(nodes) ||
2337 (!xmlXPathNodeSetContains(nodes, node)))
2338 return(ret);
2339
2340 l = xmlXPathNodeSetGetLength(nodes);
2341 for (i = 0; i < l; i++) {
2342 cur = xmlXPathNodeSetItem(nodes, i);
2343 if (cur == node)
2344 break;
2345 xmlXPathNodeSetAddUnique(ret, cur);
2346 }
2347 return(ret);
2348}
2349
2350/**
2351 * xmlXPathNodeLeading:
2352 * @nodes: a node-set
2353 * @node: a node
2354 *
2355 * Implements the EXSLT - Sets leading() function:
2356 * node-set set:leading (node-set, node-set)
2357 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2358 * is called.
2359 *
2360 * Returns the nodes in @nodes that precede @node in document order,
2361 * @nodes if @node is NULL or an empty node-set if @nodes
2362 * doesn't contain @node
2363 */
2364xmlNodeSetPtr
2365xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2366 xmlXPathNodeSetSort(nodes);
2367 return(xmlXPathNodeLeadingSorted(nodes, node));
2368}
2369
2370/**
2371 * xmlXPathLeadingSorted:
2372 * @nodes1: a node-set, sorted by document order
2373 * @nodes2: a node-set, sorted by document order
2374 *
2375 * Implements the EXSLT - Sets leading() function:
2376 * node-set set:leading (node-set, node-set)
2377 *
2378 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2379 * in document order, @nodes1 if @nodes2 is NULL or empty or
2380 * an empty node-set if @nodes1 doesn't contain @nodes2
2381 */
2382xmlNodeSetPtr
2383xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2384 if (xmlXPathNodeSetIsEmpty(nodes2))
2385 return(nodes1);
2386 return(xmlXPathNodeLeadingSorted(nodes1,
2387 xmlXPathNodeSetItem(nodes2, 1)));
2388}
2389
2390/**
2391 * xmlXPathLeading:
2392 * @nodes1: a node-set
2393 * @nodes2: a node-set
2394 *
2395 * Implements the EXSLT - Sets leading() function:
2396 * node-set set:leading (node-set, node-set)
2397 * @nodes1 and @nodes2 are sorted by document order, then
2398 * #exslSetsLeadingSorted is called.
2399 *
2400 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2401 * in document order, @nodes1 if @nodes2 is NULL or empty or
2402 * an empty node-set if @nodes1 doesn't contain @nodes2
2403 */
2404xmlNodeSetPtr
2405xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2406 if (xmlXPathNodeSetIsEmpty(nodes2))
2407 return(nodes1);
2408 if (xmlXPathNodeSetIsEmpty(nodes1))
2409 return(xmlXPathNodeSetCreate(NULL));
2410 xmlXPathNodeSetSort(nodes1);
2411 xmlXPathNodeSetSort(nodes2);
2412 return(xmlXPathNodeLeadingSorted(nodes1,
2413 xmlXPathNodeSetItem(nodes2, 1)));
2414}
2415
2416/**
2417 * xmlXPathNodeTrailingSorted:
2418 * @nodes: a node-set, sorted by document order
2419 * @node: a node
2420 *
2421 * Implements the EXSLT - Sets trailing() function:
2422 * node-set set:trailing (node-set, node-set)
2423 *
2424 * Returns the nodes in @nodes that follow @node in document order,
2425 * @nodes if @node is NULL or an empty node-set if @nodes
2426 * doesn't contain @node
2427 */
2428xmlNodeSetPtr
2429xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2430 int i, l;
2431 xmlNodePtr cur;
2432 xmlNodeSetPtr ret;
2433
2434 if (node == NULL)
2435 return(nodes);
2436
2437 ret = xmlXPathNodeSetCreate(NULL);
2438 if (xmlXPathNodeSetIsEmpty(nodes) ||
2439 (!xmlXPathNodeSetContains(nodes, node)))
2440 return(ret);
2441
2442 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002443 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002444 cur = xmlXPathNodeSetItem(nodes, i);
2445 if (cur == node)
2446 break;
2447 xmlXPathNodeSetAddUnique(ret, cur);
2448 }
2449 return(ret);
2450}
2451
2452/**
2453 * xmlXPathNodeTrailing:
2454 * @nodes: a node-set
2455 * @node: a node
2456 *
2457 * Implements the EXSLT - Sets trailing() function:
2458 * node-set set:trailing (node-set, node-set)
2459 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2460 * is called.
2461 *
2462 * Returns the nodes in @nodes that follow @node in document order,
2463 * @nodes if @node is NULL or an empty node-set if @nodes
2464 * doesn't contain @node
2465 */
2466xmlNodeSetPtr
2467xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2468 xmlXPathNodeSetSort(nodes);
2469 return(xmlXPathNodeTrailingSorted(nodes, node));
2470}
2471
2472/**
2473 * xmlXPathTrailingSorted:
2474 * @nodes1: a node-set, sorted by document order
2475 * @nodes2: a node-set, sorted by document order
2476 *
2477 * Implements the EXSLT - Sets trailing() function:
2478 * node-set set:trailing (node-set, node-set)
2479 *
2480 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2481 * in document order, @nodes1 if @nodes2 is NULL or empty or
2482 * an empty node-set if @nodes1 doesn't contain @nodes2
2483 */
2484xmlNodeSetPtr
2485xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2486 if (xmlXPathNodeSetIsEmpty(nodes2))
2487 return(nodes1);
2488 return(xmlXPathNodeTrailingSorted(nodes1,
2489 xmlXPathNodeSetItem(nodes2, 0)));
2490}
2491
2492/**
2493 * xmlXPathTrailing:
2494 * @nodes1: a node-set
2495 * @nodes2: a node-set
2496 *
2497 * Implements the EXSLT - Sets trailing() function:
2498 * node-set set:trailing (node-set, node-set)
2499 * @nodes1 and @nodes2 are sorted by document order, then
2500 * #xmlXPathTrailingSorted is called.
2501 *
2502 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2503 * in document order, @nodes1 if @nodes2 is NULL or empty or
2504 * an empty node-set if @nodes1 doesn't contain @nodes2
2505 */
2506xmlNodeSetPtr
2507xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2508 if (xmlXPathNodeSetIsEmpty(nodes2))
2509 return(nodes1);
2510 if (xmlXPathNodeSetIsEmpty(nodes1))
2511 return(xmlXPathNodeSetCreate(NULL));
2512 xmlXPathNodeSetSort(nodes1);
2513 xmlXPathNodeSetSort(nodes2);
2514 return(xmlXPathNodeTrailingSorted(nodes1,
2515 xmlXPathNodeSetItem(nodes2, 0)));
2516}
2517
Owen Taylor3473f882001-02-23 17:55:21 +00002518/************************************************************************
2519 * *
2520 * Routines to handle extra functions *
2521 * *
2522 ************************************************************************/
2523
2524/**
2525 * xmlXPathRegisterFunc:
2526 * @ctxt: the XPath context
2527 * @name: the function name
2528 * @f: the function implementation or NULL
2529 *
2530 * Register a new function. If @f is NULL it unregisters the function
2531 *
2532 * Returns 0 in case of success, -1 in case of error
2533 */
2534int
2535xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2536 xmlXPathFunction f) {
2537 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2538}
2539
2540/**
2541 * xmlXPathRegisterFuncNS:
2542 * @ctxt: the XPath context
2543 * @name: the function name
2544 * @ns_uri: the function namespace URI
2545 * @f: the function implementation or NULL
2546 *
2547 * Register a new function. If @f is NULL it unregisters the function
2548 *
2549 * Returns 0 in case of success, -1 in case of error
2550 */
2551int
2552xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2553 const xmlChar *ns_uri, xmlXPathFunction f) {
2554 if (ctxt == NULL)
2555 return(-1);
2556 if (name == NULL)
2557 return(-1);
2558
2559 if (ctxt->funcHash == NULL)
2560 ctxt->funcHash = xmlHashCreate(0);
2561 if (ctxt->funcHash == NULL)
2562 return(-1);
2563 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2564}
2565
2566/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002567 * xmlXPathRegisterFuncLookup:
2568 * @ctxt: the XPath context
2569 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002570 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00002571 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002572 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00002573 */
2574void
2575xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2576 xmlXPathFuncLookupFunc f,
2577 void *funcCtxt) {
2578 if (ctxt == NULL)
2579 return;
2580 ctxt->funcLookupFunc = (void *) f;
2581 ctxt->funcLookupData = funcCtxt;
2582}
2583
2584/**
Owen Taylor3473f882001-02-23 17:55:21 +00002585 * xmlXPathFunctionLookup:
2586 * @ctxt: the XPath context
2587 * @name: the function name
2588 *
2589 * Search in the Function array of the context for the given
2590 * function.
2591 *
2592 * Returns the xmlXPathFunction or NULL if not found
2593 */
2594xmlXPathFunction
2595xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002596 if (ctxt == NULL)
2597 return (NULL);
2598
2599 if (ctxt->funcLookupFunc != NULL) {
2600 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002601 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002602
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002603 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002604 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002605 if (ret != NULL)
2606 return(ret);
2607 }
Owen Taylor3473f882001-02-23 17:55:21 +00002608 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2609}
2610
2611/**
2612 * xmlXPathFunctionLookupNS:
2613 * @ctxt: the XPath context
2614 * @name: the function name
2615 * @ns_uri: the function namespace URI
2616 *
2617 * Search in the Function array of the context for the given
2618 * function.
2619 *
2620 * Returns the xmlXPathFunction or NULL if not found
2621 */
2622xmlXPathFunction
2623xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2624 const xmlChar *ns_uri) {
2625 if (ctxt == NULL)
2626 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002627 if (name == NULL)
2628 return(NULL);
2629
Thomas Broyerba4ad322001-07-26 16:55:21 +00002630 if (ctxt->funcLookupFunc != NULL) {
2631 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002632 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002633
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002634 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002635 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002636 if (ret != NULL)
2637 return(ret);
2638 }
2639
2640 if (ctxt->funcHash == NULL)
2641 return(NULL);
2642
Owen Taylor3473f882001-02-23 17:55:21 +00002643 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2644}
2645
2646/**
2647 * xmlXPathRegisteredFuncsCleanup:
2648 * @ctxt: the XPath context
2649 *
2650 * Cleanup the XPath context data associated to registered functions
2651 */
2652void
2653xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2654 if (ctxt == NULL)
2655 return;
2656
2657 xmlHashFree(ctxt->funcHash, NULL);
2658 ctxt->funcHash = NULL;
2659}
2660
2661/************************************************************************
2662 * *
2663 * Routines to handle Variable *
2664 * *
2665 ************************************************************************/
2666
2667/**
2668 * xmlXPathRegisterVariable:
2669 * @ctxt: the XPath context
2670 * @name: the variable name
2671 * @value: the variable value or NULL
2672 *
2673 * Register a new variable value. If @value is NULL it unregisters
2674 * the variable
2675 *
2676 * Returns 0 in case of success, -1 in case of error
2677 */
2678int
2679xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2680 xmlXPathObjectPtr value) {
2681 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2682}
2683
2684/**
2685 * xmlXPathRegisterVariableNS:
2686 * @ctxt: the XPath context
2687 * @name: the variable name
2688 * @ns_uri: the variable namespace URI
2689 * @value: the variable value or NULL
2690 *
2691 * Register a new variable value. If @value is NULL it unregisters
2692 * the variable
2693 *
2694 * Returns 0 in case of success, -1 in case of error
2695 */
2696int
2697xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2698 const xmlChar *ns_uri,
2699 xmlXPathObjectPtr value) {
2700 if (ctxt == NULL)
2701 return(-1);
2702 if (name == NULL)
2703 return(-1);
2704
2705 if (ctxt->varHash == NULL)
2706 ctxt->varHash = xmlHashCreate(0);
2707 if (ctxt->varHash == NULL)
2708 return(-1);
2709 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2710 (void *) value,
2711 (xmlHashDeallocator)xmlXPathFreeObject));
2712}
2713
2714/**
2715 * xmlXPathRegisterVariableLookup:
2716 * @ctxt: the XPath context
2717 * @f: the lookup function
2718 * @data: the lookup data
2719 *
2720 * register an external mechanism to do variable lookup
2721 */
2722void
2723xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2724 xmlXPathVariableLookupFunc f, void *data) {
2725 if (ctxt == NULL)
2726 return;
2727 ctxt->varLookupFunc = (void *) f;
2728 ctxt->varLookupData = data;
2729}
2730
2731/**
2732 * xmlXPathVariableLookup:
2733 * @ctxt: the XPath context
2734 * @name: the variable name
2735 *
2736 * Search in the Variable array of the context for the given
2737 * variable value.
2738 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002739 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002740 */
2741xmlXPathObjectPtr
2742xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2743 if (ctxt == NULL)
2744 return(NULL);
2745
2746 if (ctxt->varLookupFunc != NULL) {
2747 xmlXPathObjectPtr ret;
2748
2749 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2750 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00002751 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002752 }
2753 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
2754}
2755
2756/**
2757 * xmlXPathVariableLookupNS:
2758 * @ctxt: the XPath context
2759 * @name: the variable name
2760 * @ns_uri: the variable namespace URI
2761 *
2762 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00002763 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00002764 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002765 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002766 */
2767xmlXPathObjectPtr
2768xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2769 const xmlChar *ns_uri) {
2770 if (ctxt == NULL)
2771 return(NULL);
2772
2773 if (ctxt->varLookupFunc != NULL) {
2774 xmlXPathObjectPtr ret;
2775
2776 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2777 (ctxt->varLookupData, name, ns_uri);
2778 if (ret != NULL) return(ret);
2779 }
2780
2781 if (ctxt->varHash == NULL)
2782 return(NULL);
2783 if (name == NULL)
2784 return(NULL);
2785
Daniel Veillard8c357d52001-07-03 23:43:33 +00002786 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
2787 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00002788}
2789
2790/**
2791 * xmlXPathRegisteredVariablesCleanup:
2792 * @ctxt: the XPath context
2793 *
2794 * Cleanup the XPath context data associated to registered variables
2795 */
2796void
2797xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
2798 if (ctxt == NULL)
2799 return;
2800
Daniel Veillard76d66f42001-05-16 21:05:17 +00002801 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00002802 ctxt->varHash = NULL;
2803}
2804
2805/**
2806 * xmlXPathRegisterNs:
2807 * @ctxt: the XPath context
2808 * @prefix: the namespace prefix
2809 * @ns_uri: the namespace name
2810 *
2811 * Register a new namespace. If @ns_uri is NULL it unregisters
2812 * the namespace
2813 *
2814 * Returns 0 in case of success, -1 in case of error
2815 */
2816int
2817xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
2818 const xmlChar *ns_uri) {
2819 if (ctxt == NULL)
2820 return(-1);
2821 if (prefix == NULL)
2822 return(-1);
2823
2824 if (ctxt->nsHash == NULL)
2825 ctxt->nsHash = xmlHashCreate(10);
2826 if (ctxt->nsHash == NULL)
2827 return(-1);
2828 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) ns_uri,
2829 (xmlHashDeallocator)xmlFree));
2830}
2831
2832/**
2833 * xmlXPathNsLookup:
2834 * @ctxt: the XPath context
2835 * @prefix: the namespace prefix value
2836 *
2837 * Search in the namespace declaration array of the context for the given
2838 * namespace name associated to the given prefix
2839 *
2840 * Returns the value or NULL if not found
2841 */
2842const xmlChar *
2843xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
2844 if (ctxt == NULL)
2845 return(NULL);
2846 if (prefix == NULL)
2847 return(NULL);
2848
2849#ifdef XML_XML_NAMESPACE
2850 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
2851 return(XML_XML_NAMESPACE);
2852#endif
2853
Daniel Veillardc8f620b2001-04-30 20:31:33 +00002854 if (ctxt->namespaces != NULL) {
2855 int i;
2856
2857 for (i = 0;i < ctxt->nsNr;i++) {
2858 if ((ctxt->namespaces[i] != NULL) &&
2859 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
2860 return(ctxt->namespaces[i]->href);
2861 }
2862 }
Owen Taylor3473f882001-02-23 17:55:21 +00002863
2864 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
2865}
2866
2867/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002868 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00002869 * @ctxt: the XPath context
2870 *
2871 * Cleanup the XPath context data associated to registered variables
2872 */
2873void
2874xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
2875 if (ctxt == NULL)
2876 return;
2877
2878 xmlHashFree(ctxt->nsHash, NULL);
2879 ctxt->nsHash = NULL;
2880}
2881
2882/************************************************************************
2883 * *
2884 * Routines to handle Values *
2885 * *
2886 ************************************************************************/
2887
2888/* Allocations are terrible, one need to optimize all this !!! */
2889
2890/**
2891 * xmlXPathNewFloat:
2892 * @val: the double value
2893 *
2894 * Create a new xmlXPathObjectPtr of type double and of value @val
2895 *
2896 * Returns the newly created object.
2897 */
2898xmlXPathObjectPtr
2899xmlXPathNewFloat(double val) {
2900 xmlXPathObjectPtr ret;
2901
2902 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2903 if (ret == NULL) {
2904 xmlGenericError(xmlGenericErrorContext,
2905 "xmlXPathNewFloat: out of memory\n");
2906 return(NULL);
2907 }
2908 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2909 ret->type = XPATH_NUMBER;
2910 ret->floatval = val;
2911 return(ret);
2912}
2913
2914/**
2915 * xmlXPathNewBoolean:
2916 * @val: the boolean value
2917 *
2918 * Create a new xmlXPathObjectPtr of type boolean and of value @val
2919 *
2920 * Returns the newly created object.
2921 */
2922xmlXPathObjectPtr
2923xmlXPathNewBoolean(int val) {
2924 xmlXPathObjectPtr ret;
2925
2926 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2927 if (ret == NULL) {
2928 xmlGenericError(xmlGenericErrorContext,
2929 "xmlXPathNewBoolean: out of memory\n");
2930 return(NULL);
2931 }
2932 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2933 ret->type = XPATH_BOOLEAN;
2934 ret->boolval = (val != 0);
2935 return(ret);
2936}
2937
2938/**
2939 * xmlXPathNewString:
2940 * @val: the xmlChar * value
2941 *
2942 * Create a new xmlXPathObjectPtr of type string and of value @val
2943 *
2944 * Returns the newly created object.
2945 */
2946xmlXPathObjectPtr
2947xmlXPathNewString(const xmlChar *val) {
2948 xmlXPathObjectPtr ret;
2949
2950 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2951 if (ret == NULL) {
2952 xmlGenericError(xmlGenericErrorContext,
2953 "xmlXPathNewString: out of memory\n");
2954 return(NULL);
2955 }
2956 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2957 ret->type = XPATH_STRING;
2958 if (val != NULL)
2959 ret->stringval = xmlStrdup(val);
2960 else
2961 ret->stringval = xmlStrdup((const xmlChar *)"");
2962 return(ret);
2963}
2964
2965/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002966 * xmlXPathWrapString:
2967 * @val: the xmlChar * value
2968 *
2969 * Wraps the @val string into an XPath object.
2970 *
2971 * Returns the newly created object.
2972 */
2973xmlXPathObjectPtr
2974xmlXPathWrapString (xmlChar *val) {
2975 xmlXPathObjectPtr ret;
2976
2977 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2978 if (ret == NULL) {
2979 xmlGenericError(xmlGenericErrorContext,
2980 "xmlXPathWrapString: out of memory\n");
2981 return(NULL);
2982 }
2983 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2984 ret->type = XPATH_STRING;
2985 ret->stringval = val;
2986 return(ret);
2987}
2988
2989/**
Owen Taylor3473f882001-02-23 17:55:21 +00002990 * xmlXPathNewCString:
2991 * @val: the char * value
2992 *
2993 * Create a new xmlXPathObjectPtr of type string and of value @val
2994 *
2995 * Returns the newly created object.
2996 */
2997xmlXPathObjectPtr
2998xmlXPathNewCString(const char *val) {
2999 xmlXPathObjectPtr ret;
3000
3001 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3002 if (ret == NULL) {
3003 xmlGenericError(xmlGenericErrorContext,
3004 "xmlXPathNewCString: out of memory\n");
3005 return(NULL);
3006 }
3007 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3008 ret->type = XPATH_STRING;
3009 ret->stringval = xmlStrdup(BAD_CAST val);
3010 return(ret);
3011}
3012
3013/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003014 * xmlXPathWrapCString:
3015 * @val: the char * value
3016 *
3017 * Wraps a string into an XPath object.
3018 *
3019 * Returns the newly created object.
3020 */
3021xmlXPathObjectPtr
3022xmlXPathWrapCString (char * val) {
3023 return(xmlXPathWrapString((xmlChar *)(val)));
3024}
3025
3026/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003027 * xmlXPathWrapExternal:
3028 * @val: the user data
3029 *
3030 * Wraps the @val data into an XPath object.
3031 *
3032 * Returns the newly created object.
3033 */
3034xmlXPathObjectPtr
3035xmlXPathWrapExternal (void *val) {
3036 xmlXPathObjectPtr ret;
3037
3038 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3039 if (ret == NULL) {
3040 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003041 "xmlXPathWrapExternal: out of memory\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003042 return(NULL);
3043 }
3044 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3045 ret->type = XPATH_USERS;
3046 ret->user = val;
3047 return(ret);
3048}
3049
3050/**
Owen Taylor3473f882001-02-23 17:55:21 +00003051 * xmlXPathObjectCopy:
3052 * @val: the original object
3053 *
3054 * allocate a new copy of a given object
3055 *
3056 * Returns the newly created object.
3057 */
3058xmlXPathObjectPtr
3059xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3060 xmlXPathObjectPtr ret;
3061
3062 if (val == NULL)
3063 return(NULL);
3064
3065 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3066 if (ret == NULL) {
3067 xmlGenericError(xmlGenericErrorContext,
3068 "xmlXPathObjectCopy: out of memory\n");
3069 return(NULL);
3070 }
3071 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3072 switch (val->type) {
3073 case XPATH_BOOLEAN:
3074 case XPATH_NUMBER:
3075 case XPATH_POINT:
3076 case XPATH_RANGE:
3077 break;
3078 case XPATH_STRING:
3079 ret->stringval = xmlStrdup(val->stringval);
3080 break;
3081 case XPATH_XSLT_TREE:
3082 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003083 (val->nodesetval->nodeTab != NULL)) {
3084 ret->boolval = 1;
Daniel Veillard6ab38382001-10-06 13:08:27 +00003085 ret->user = xmlDocCopyNode(val->nodesetval->nodeTab[0],
3086 val->nodesetval->nodeTab[0]->doc, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003087 ret->nodesetval = xmlXPathNodeSetCreate(
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003088 (xmlNodePtr) ret->user);
3089 } else
Owen Taylor3473f882001-02-23 17:55:21 +00003090 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003091 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00003092 break;
3093 case XPATH_NODESET:
3094 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003095 /* Do not deallocate the copied tree value */
3096 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003097 break;
3098 case XPATH_LOCATIONSET:
3099#ifdef LIBXML_XPTR_ENABLED
3100 {
3101 xmlLocationSetPtr loc = val->user;
3102 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3103 break;
3104 }
3105#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00003106 case XPATH_USERS:
3107 ret->user = val->user;
3108 break;
3109 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00003110 xmlGenericError(xmlGenericErrorContext,
3111 "xmlXPathObjectCopy: unsupported type %d\n",
3112 val->type);
3113 break;
3114 }
3115 return(ret);
3116}
3117
3118/**
3119 * xmlXPathFreeObject:
3120 * @obj: the object to free
3121 *
3122 * Free up an xmlXPathObjectPtr object.
3123 */
3124void
3125xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3126 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003127 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00003128 if (obj->boolval) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003129 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003130 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00003131 xmlFreeNodeList((xmlNodePtr) obj->user);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003132 } else if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00003133 xmlXPathFreeValueTree(obj->nodesetval);
3134 } else {
3135 if (obj->nodesetval != NULL)
3136 xmlXPathFreeNodeSet(obj->nodesetval);
3137 }
Owen Taylor3473f882001-02-23 17:55:21 +00003138#ifdef LIBXML_XPTR_ENABLED
3139 } else if (obj->type == XPATH_LOCATIONSET) {
3140 if (obj->user != NULL)
3141 xmlXPtrFreeLocationSet(obj->user);
3142#endif
3143 } else if (obj->type == XPATH_STRING) {
3144 if (obj->stringval != NULL)
3145 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00003146 }
3147
Owen Taylor3473f882001-02-23 17:55:21 +00003148 xmlFree(obj);
3149}
3150
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003151
3152/************************************************************************
3153 * *
3154 * Type Casting Routines *
3155 * *
3156 ************************************************************************/
3157
3158/**
3159 * xmlXPathCastBooleanToString:
3160 * @val: a boolean
3161 *
3162 * Converts a boolean to its string value.
3163 *
3164 * Returns a newly allocated string.
3165 */
3166xmlChar *
3167xmlXPathCastBooleanToString (int val) {
3168 xmlChar *ret;
3169 if (val)
3170 ret = xmlStrdup((const xmlChar *) "true");
3171 else
3172 ret = xmlStrdup((const xmlChar *) "false");
3173 return(ret);
3174}
3175
3176/**
3177 * xmlXPathCastNumberToString:
3178 * @val: a number
3179 *
3180 * Converts a number to its string value.
3181 *
3182 * Returns a newly allocated string.
3183 */
3184xmlChar *
3185xmlXPathCastNumberToString (double val) {
3186 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00003187 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003188 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003189 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003190 break;
3191 case -1:
3192 ret = xmlStrdup((const xmlChar *) "-Infinity");
3193 break;
3194 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003195 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003196 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00003197 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
3198 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003199 } else {
3200 /* could be improved */
3201 char buf[100];
3202 xmlXPathFormatNumber(val, buf, 100);
3203 ret = xmlStrdup((const xmlChar *) buf);
3204 }
3205 }
3206 return(ret);
3207}
3208
3209/**
3210 * xmlXPathCastNodeToString:
3211 * @node: a node
3212 *
3213 * Converts a node to its string value.
3214 *
3215 * Returns a newly allocated string.
3216 */
3217xmlChar *
3218xmlXPathCastNodeToString (xmlNodePtr node) {
3219 return(xmlNodeGetContent(node));
3220}
3221
3222/**
3223 * xmlXPathCastNodeSetToString:
3224 * @ns: a node-set
3225 *
3226 * Converts a node-set to its string value.
3227 *
3228 * Returns a newly allocated string.
3229 */
3230xmlChar *
3231xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3232 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3233 return(xmlStrdup((const xmlChar *) ""));
3234
3235 xmlXPathNodeSetSort(ns);
3236 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3237}
3238
3239/**
3240 * xmlXPathCastToString:
3241 * @val: an XPath object
3242 *
3243 * Converts an existing object to its string() equivalent
3244 *
3245 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003246 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003247 * string object).
3248 */
3249xmlChar *
3250xmlXPathCastToString(xmlXPathObjectPtr val) {
3251 xmlChar *ret = NULL;
3252
3253 if (val == NULL)
3254 return(xmlStrdup((const xmlChar *) ""));
3255 switch (val->type) {
3256 case XPATH_UNDEFINED:
3257#ifdef DEBUG_EXPR
3258 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3259#endif
3260 ret = xmlStrdup((const xmlChar *) "");
3261 break;
3262 case XPATH_XSLT_TREE:
3263 case XPATH_NODESET:
3264 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3265 break;
3266 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00003267 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003268 case XPATH_BOOLEAN:
3269 ret = xmlXPathCastBooleanToString(val->boolval);
3270 break;
3271 case XPATH_NUMBER: {
3272 ret = xmlXPathCastNumberToString(val->floatval);
3273 break;
3274 }
3275 case XPATH_USERS:
3276 case XPATH_POINT:
3277 case XPATH_RANGE:
3278 case XPATH_LOCATIONSET:
3279 TODO
3280 ret = xmlStrdup((const xmlChar *) "");
3281 break;
3282 }
3283 return(ret);
3284}
3285
3286/**
3287 * xmlXPathConvertString:
3288 * @val: an XPath object
3289 *
3290 * Converts an existing object to its string() equivalent
3291 *
3292 * Returns the new object, the old one is freed (or the operation
3293 * is done directly on @val)
3294 */
3295xmlXPathObjectPtr
3296xmlXPathConvertString(xmlXPathObjectPtr val) {
3297 xmlChar *res = NULL;
3298
3299 if (val == NULL)
3300 return(xmlXPathNewCString(""));
3301
3302 switch (val->type) {
3303 case XPATH_UNDEFINED:
3304#ifdef DEBUG_EXPR
3305 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3306#endif
3307 break;
3308 case XPATH_XSLT_TREE:
3309 case XPATH_NODESET:
3310 res = xmlXPathCastNodeSetToString(val->nodesetval);
3311 break;
3312 case XPATH_STRING:
3313 return(val);
3314 case XPATH_BOOLEAN:
3315 res = xmlXPathCastBooleanToString(val->boolval);
3316 break;
3317 case XPATH_NUMBER:
3318 res = xmlXPathCastNumberToString(val->floatval);
3319 break;
3320 case XPATH_USERS:
3321 case XPATH_POINT:
3322 case XPATH_RANGE:
3323 case XPATH_LOCATIONSET:
3324 TODO;
3325 break;
3326 }
3327 xmlXPathFreeObject(val);
3328 if (res == NULL)
3329 return(xmlXPathNewCString(""));
3330 return(xmlXPathWrapString(res));
3331}
3332
3333/**
3334 * xmlXPathCastBooleanToNumber:
3335 * @val: a boolean
3336 *
3337 * Converts a boolean to its number value
3338 *
3339 * Returns the number value
3340 */
3341double
3342xmlXPathCastBooleanToNumber(int val) {
3343 if (val)
3344 return(1.0);
3345 return(0.0);
3346}
3347
3348/**
3349 * xmlXPathCastStringToNumber:
3350 * @val: a string
3351 *
3352 * Converts a string to its number value
3353 *
3354 * Returns the number value
3355 */
3356double
3357xmlXPathCastStringToNumber(const xmlChar * val) {
3358 return(xmlXPathStringEvalNumber(val));
3359}
3360
3361/**
3362 * xmlXPathCastNodeToNumber:
3363 * @node: a node
3364 *
3365 * Converts a node to its number value
3366 *
3367 * Returns the number value
3368 */
3369double
3370xmlXPathCastNodeToNumber (xmlNodePtr node) {
3371 xmlChar *strval;
3372 double ret;
3373
3374 if (node == NULL)
3375 return(xmlXPathNAN);
3376 strval = xmlXPathCastNodeToString(node);
3377 if (strval == NULL)
3378 return(xmlXPathNAN);
3379 ret = xmlXPathCastStringToNumber(strval);
3380 xmlFree(strval);
3381
3382 return(ret);
3383}
3384
3385/**
3386 * xmlXPathCastNodeSetToNumber:
3387 * @ns: a node-set
3388 *
3389 * Converts a node-set to its number value
3390 *
3391 * Returns the number value
3392 */
3393double
3394xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3395 xmlChar *str;
3396 double ret;
3397
3398 if (ns == NULL)
3399 return(xmlXPathNAN);
3400 str = xmlXPathCastNodeSetToString(ns);
3401 ret = xmlXPathCastStringToNumber(str);
3402 xmlFree(str);
3403 return(ret);
3404}
3405
3406/**
3407 * xmlXPathCastToNumber:
3408 * @val: an XPath object
3409 *
3410 * Converts an XPath object to its number value
3411 *
3412 * Returns the number value
3413 */
3414double
3415xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3416 double ret = 0.0;
3417
3418 if (val == NULL)
3419 return(xmlXPathNAN);
3420 switch (val->type) {
3421 case XPATH_UNDEFINED:
3422#ifdef DEGUB_EXPR
3423 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3424#endif
3425 ret = xmlXPathNAN;
3426 break;
3427 case XPATH_XSLT_TREE:
3428 case XPATH_NODESET:
3429 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3430 break;
3431 case XPATH_STRING:
3432 ret = xmlXPathCastStringToNumber(val->stringval);
3433 break;
3434 case XPATH_NUMBER:
3435 ret = val->floatval;
3436 break;
3437 case XPATH_BOOLEAN:
3438 ret = xmlXPathCastBooleanToNumber(val->boolval);
3439 break;
3440 case XPATH_USERS:
3441 case XPATH_POINT:
3442 case XPATH_RANGE:
3443 case XPATH_LOCATIONSET:
3444 TODO;
3445 ret = xmlXPathNAN;
3446 break;
3447 }
3448 return(ret);
3449}
3450
3451/**
3452 * xmlXPathConvertNumber:
3453 * @val: an XPath object
3454 *
3455 * Converts an existing object to its number() equivalent
3456 *
3457 * Returns the new object, the old one is freed (or the operation
3458 * is done directly on @val)
3459 */
3460xmlXPathObjectPtr
3461xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3462 xmlXPathObjectPtr ret;
3463
3464 if (val == NULL)
3465 return(xmlXPathNewFloat(0.0));
3466 if (val->type == XPATH_NUMBER)
3467 return(val);
3468 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3469 xmlXPathFreeObject(val);
3470 return(ret);
3471}
3472
3473/**
3474 * xmlXPathCastNumberToBoolean:
3475 * @val: a number
3476 *
3477 * Converts a number to its boolean value
3478 *
3479 * Returns the boolean value
3480 */
3481int
3482xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003483 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003484 return(0);
3485 return(1);
3486}
3487
3488/**
3489 * xmlXPathCastStringToBoolean:
3490 * @val: a string
3491 *
3492 * Converts a string to its boolean value
3493 *
3494 * Returns the boolean value
3495 */
3496int
3497xmlXPathCastStringToBoolean (const xmlChar *val) {
3498 if ((val == NULL) || (xmlStrlen(val) == 0))
3499 return(0);
3500 return(1);
3501}
3502
3503/**
3504 * xmlXPathCastNodeSetToBoolean:
3505 * @ns: a node-set
3506 *
3507 * Converts a node-set to its boolean value
3508 *
3509 * Returns the boolean value
3510 */
3511int
3512xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3513 if ((ns == NULL) || (ns->nodeNr == 0))
3514 return(0);
3515 return(1);
3516}
3517
3518/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003519 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003520 * @val: an XPath object
3521 *
3522 * Converts an XPath object to its boolean value
3523 *
3524 * Returns the boolean value
3525 */
3526int
3527xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3528 int ret = 0;
3529
3530 if (val == NULL)
3531 return(0);
3532 switch (val->type) {
3533 case XPATH_UNDEFINED:
3534#ifdef DEBUG_EXPR
3535 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3536#endif
3537 ret = 0;
3538 break;
3539 case XPATH_XSLT_TREE:
3540 case XPATH_NODESET:
3541 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3542 break;
3543 case XPATH_STRING:
3544 ret = xmlXPathCastStringToBoolean(val->stringval);
3545 break;
3546 case XPATH_NUMBER:
3547 ret = xmlXPathCastNumberToBoolean(val->floatval);
3548 break;
3549 case XPATH_BOOLEAN:
3550 ret = val->boolval;
3551 break;
3552 case XPATH_USERS:
3553 case XPATH_POINT:
3554 case XPATH_RANGE:
3555 case XPATH_LOCATIONSET:
3556 TODO;
3557 ret = 0;
3558 break;
3559 }
3560 return(ret);
3561}
3562
3563
3564/**
3565 * xmlXPathConvertBoolean:
3566 * @val: an XPath object
3567 *
3568 * Converts an existing object to its boolean() equivalent
3569 *
3570 * Returns the new object, the old one is freed (or the operation
3571 * is done directly on @val)
3572 */
3573xmlXPathObjectPtr
3574xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3575 xmlXPathObjectPtr ret;
3576
3577 if (val == NULL)
3578 return(xmlXPathNewBoolean(0));
3579 if (val->type == XPATH_BOOLEAN)
3580 return(val);
3581 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3582 xmlXPathFreeObject(val);
3583 return(ret);
3584}
3585
Owen Taylor3473f882001-02-23 17:55:21 +00003586/************************************************************************
3587 * *
3588 * Routines to handle XPath contexts *
3589 * *
3590 ************************************************************************/
3591
3592/**
3593 * xmlXPathNewContext:
3594 * @doc: the XML document
3595 *
3596 * Create a new xmlXPathContext
3597 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00003598 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00003599 */
3600xmlXPathContextPtr
3601xmlXPathNewContext(xmlDocPtr doc) {
3602 xmlXPathContextPtr ret;
3603
3604 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3605 if (ret == NULL) {
3606 xmlGenericError(xmlGenericErrorContext,
3607 "xmlXPathNewContext: out of memory\n");
3608 return(NULL);
3609 }
3610 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3611 ret->doc = doc;
3612 ret->node = NULL;
3613
3614 ret->varHash = NULL;
3615
3616 ret->nb_types = 0;
3617 ret->max_types = 0;
3618 ret->types = NULL;
3619
3620 ret->funcHash = xmlHashCreate(0);
3621
3622 ret->nb_axis = 0;
3623 ret->max_axis = 0;
3624 ret->axis = NULL;
3625
3626 ret->nsHash = NULL;
3627 ret->user = NULL;
3628
3629 ret->contextSize = -1;
3630 ret->proximityPosition = -1;
3631
3632 xmlXPathRegisterAllFunctions(ret);
3633
3634 return(ret);
3635}
3636
3637/**
3638 * xmlXPathFreeContext:
3639 * @ctxt: the context to free
3640 *
3641 * Free up an xmlXPathContext
3642 */
3643void
3644xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3645 xmlXPathRegisteredNsCleanup(ctxt);
3646 xmlXPathRegisteredFuncsCleanup(ctxt);
3647 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003648 xmlFree(ctxt);
3649}
3650
3651/************************************************************************
3652 * *
3653 * Routines to handle XPath parser contexts *
3654 * *
3655 ************************************************************************/
3656
3657#define CHECK_CTXT(ctxt) \
3658 if (ctxt == NULL) { \
3659 xmlGenericError(xmlGenericErrorContext, \
3660 "%s:%d Internal error: ctxt == NULL\n", \
3661 __FILE__, __LINE__); \
3662 } \
3663
3664
3665#define CHECK_CONTEXT(ctxt) \
3666 if (ctxt == NULL) { \
3667 xmlGenericError(xmlGenericErrorContext, \
3668 "%s:%d Internal error: no context\n", \
3669 __FILE__, __LINE__); \
3670 } \
3671 else if (ctxt->doc == NULL) { \
3672 xmlGenericError(xmlGenericErrorContext, \
3673 "%s:%d Internal error: no document\n", \
3674 __FILE__, __LINE__); \
3675 } \
3676 else if (ctxt->doc->children == NULL) { \
3677 xmlGenericError(xmlGenericErrorContext, \
3678 "%s:%d Internal error: document without root\n", \
3679 __FILE__, __LINE__); \
3680 } \
3681
3682
3683/**
3684 * xmlXPathNewParserContext:
3685 * @str: the XPath expression
3686 * @ctxt: the XPath context
3687 *
3688 * Create a new xmlXPathParserContext
3689 *
3690 * Returns the xmlXPathParserContext just allocated.
3691 */
3692xmlXPathParserContextPtr
3693xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3694 xmlXPathParserContextPtr ret;
3695
3696 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3697 if (ret == NULL) {
3698 xmlGenericError(xmlGenericErrorContext,
3699 "xmlXPathNewParserContext: out of memory\n");
3700 return(NULL);
3701 }
3702 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3703 ret->cur = ret->base = str;
3704 ret->context = ctxt;
3705
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003706 ret->comp = xmlXPathNewCompExpr();
3707 if (ret->comp == NULL) {
3708 xmlFree(ret->valueTab);
3709 xmlFree(ret);
3710 return(NULL);
3711 }
3712
3713 return(ret);
3714}
3715
3716/**
3717 * xmlXPathCompParserContext:
3718 * @comp: the XPath compiled expression
3719 * @ctxt: the XPath context
3720 *
3721 * Create a new xmlXPathParserContext when processing a compiled expression
3722 *
3723 * Returns the xmlXPathParserContext just allocated.
3724 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003725static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003726xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3727 xmlXPathParserContextPtr ret;
3728
3729 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3730 if (ret == NULL) {
3731 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003732 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003733 return(NULL);
3734 }
3735 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3736
Owen Taylor3473f882001-02-23 17:55:21 +00003737 /* Allocate the value stack */
3738 ret->valueTab = (xmlXPathObjectPtr *)
3739 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003740 if (ret->valueTab == NULL) {
3741 xmlFree(ret);
3742 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003743 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003744 return(NULL);
3745 }
Owen Taylor3473f882001-02-23 17:55:21 +00003746 ret->valueNr = 0;
3747 ret->valueMax = 10;
3748 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003749
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00003750 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003751 ret->comp = comp;
3752
Owen Taylor3473f882001-02-23 17:55:21 +00003753 return(ret);
3754}
3755
3756/**
3757 * xmlXPathFreeParserContext:
3758 * @ctxt: the context to free
3759 *
3760 * Free up an xmlXPathParserContext
3761 */
3762void
3763xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
3764 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003765 xmlFree(ctxt->valueTab);
3766 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003767 if (ctxt->comp)
3768 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00003769 xmlFree(ctxt);
3770}
3771
3772/************************************************************************
3773 * *
3774 * The implicit core function library *
3775 * *
3776 ************************************************************************/
3777
Owen Taylor3473f882001-02-23 17:55:21 +00003778/**
Daniel Veillardf06307e2001-07-03 10:35:50 +00003779 * xmlXPathNodeStringHash:
3780 * @node: a node pointer
3781 *
3782 * Function computing the beginning of the string value of the node,
3783 * used to speed up comparisons
3784 *
3785 * Returns an int usable as a hash
3786 */
3787static unsigned int
3788xmlXPathNodeValHash(xmlNodePtr node) {
3789 int len = 2;
3790 const xmlChar * string = NULL;
3791 xmlNodePtr tmp = NULL;
3792 unsigned int ret = 0;
3793
3794 if (node == NULL)
3795 return(0);
3796
3797
3798 switch (node->type) {
3799 case XML_COMMENT_NODE:
3800 case XML_PI_NODE:
3801 case XML_CDATA_SECTION_NODE:
3802 case XML_TEXT_NODE:
3803 string = node->content;
3804 if (string == NULL)
3805 return(0);
3806 if (string[0] == 0)
3807 return(0);
3808 return(((unsigned int) string[0]) +
3809 (((unsigned int) string[1]) << 8));
3810 case XML_NAMESPACE_DECL:
3811 string = ((xmlNsPtr)node)->href;
3812 if (string == NULL)
3813 return(0);
3814 if (string[0] == 0)
3815 return(0);
3816 return(((unsigned int) string[0]) +
3817 (((unsigned int) string[1]) << 8));
3818 case XML_ATTRIBUTE_NODE:
3819 tmp = ((xmlAttrPtr) node)->children;
3820 break;
3821 case XML_ELEMENT_NODE:
3822 tmp = node->children;
3823 break;
3824 default:
3825 return(0);
3826 }
3827 while (tmp != NULL) {
3828 switch (tmp->type) {
3829 case XML_COMMENT_NODE:
3830 case XML_PI_NODE:
3831 case XML_CDATA_SECTION_NODE:
3832 case XML_TEXT_NODE:
3833 string = tmp->content;
3834 break;
3835 case XML_NAMESPACE_DECL:
3836 string = ((xmlNsPtr)tmp)->href;
3837 break;
3838 default:
3839 break;
3840 }
3841 if ((string != NULL) && (string[0] != 0)) {
3842 if (string[0] == 0)
3843 return(0);
3844 if (len == 1) {
3845 return(ret + (((unsigned int) string[0]) << 8));
3846 }
3847 if (string[1] == 0) {
3848 len = 1;
3849 ret = (unsigned int) string[0];
3850 } else {
3851 return(((unsigned int) string[0]) +
3852 (((unsigned int) string[1]) << 8));
3853 }
3854 }
3855 /*
3856 * Skip to next node
3857 */
3858 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
3859 if (tmp->children->type != XML_ENTITY_DECL) {
3860 tmp = tmp->children;
3861 continue;
3862 }
3863 }
3864 if (tmp == node)
3865 break;
3866
3867 if (tmp->next != NULL) {
3868 tmp = tmp->next;
3869 continue;
3870 }
3871
3872 do {
3873 tmp = tmp->parent;
3874 if (tmp == NULL)
3875 break;
3876 if (tmp == node) {
3877 tmp = NULL;
3878 break;
3879 }
3880 if (tmp->next != NULL) {
3881 tmp = tmp->next;
3882 break;
3883 }
3884 } while (tmp != NULL);
3885 }
3886 return(ret);
3887}
3888
3889/**
3890 * xmlXPathStringHash:
3891 * @string: a string
3892 *
3893 * Function computing the beginning of the string value of the node,
3894 * used to speed up comparisons
3895 *
3896 * Returns an int usable as a hash
3897 */
3898static unsigned int
3899xmlXPathStringHash(const xmlChar * string) {
3900 if (string == NULL)
3901 return((unsigned int) 0);
3902 if (string[0] == 0)
3903 return(0);
3904 return(((unsigned int) string[0]) +
3905 (((unsigned int) string[1]) << 8));
3906}
3907
3908/**
Owen Taylor3473f882001-02-23 17:55:21 +00003909 * xmlXPathCompareNodeSetFloat:
3910 * @ctxt: the XPath Parser context
3911 * @inf: less than (1) or greater than (0)
3912 * @strict: is the comparison strict
3913 * @arg: the node set
3914 * @f: the value
3915 *
3916 * Implement the compare operation between a nodeset and a number
3917 * @ns < @val (1, 1, ...
3918 * @ns <= @val (1, 0, ...
3919 * @ns > @val (0, 1, ...
3920 * @ns >= @val (0, 0, ...
3921 *
3922 * If one object to be compared is a node-set and the other is a number,
3923 * then the comparison will be true if and only if there is a node in the
3924 * node-set such that the result of performing the comparison on the number
3925 * to be compared and on the result of converting the string-value of that
3926 * node to a number using the number function is true.
3927 *
3928 * Returns 0 or 1 depending on the results of the test.
3929 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003930static int
Owen Taylor3473f882001-02-23 17:55:21 +00003931xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
3932 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
3933 int i, ret = 0;
3934 xmlNodeSetPtr ns;
3935 xmlChar *str2;
3936
3937 if ((f == NULL) || (arg == NULL) ||
3938 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3939 xmlXPathFreeObject(arg);
3940 xmlXPathFreeObject(f);
3941 return(0);
3942 }
3943 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003944 if (ns != NULL) {
3945 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003946 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003947 if (str2 != NULL) {
3948 valuePush(ctxt,
3949 xmlXPathNewString(str2));
3950 xmlFree(str2);
3951 xmlXPathNumberFunction(ctxt, 1);
3952 valuePush(ctxt, xmlXPathObjectCopy(f));
3953 ret = xmlXPathCompareValues(ctxt, inf, strict);
3954 if (ret)
3955 break;
3956 }
3957 }
Owen Taylor3473f882001-02-23 17:55:21 +00003958 }
3959 xmlXPathFreeObject(arg);
3960 xmlXPathFreeObject(f);
3961 return(ret);
3962}
3963
3964/**
3965 * xmlXPathCompareNodeSetString:
3966 * @ctxt: the XPath Parser context
3967 * @inf: less than (1) or greater than (0)
3968 * @strict: is the comparison strict
3969 * @arg: the node set
3970 * @s: the value
3971 *
3972 * Implement the compare operation between a nodeset and a string
3973 * @ns < @val (1, 1, ...
3974 * @ns <= @val (1, 0, ...
3975 * @ns > @val (0, 1, ...
3976 * @ns >= @val (0, 0, ...
3977 *
3978 * If one object to be compared is a node-set and the other is a string,
3979 * then the comparison will be true if and only if there is a node in
3980 * the node-set such that the result of performing the comparison on the
3981 * string-value of the node and the other string is true.
3982 *
3983 * Returns 0 or 1 depending on the results of the test.
3984 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003985static int
Owen Taylor3473f882001-02-23 17:55:21 +00003986xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
3987 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
3988 int i, ret = 0;
3989 xmlNodeSetPtr ns;
3990 xmlChar *str2;
3991
3992 if ((s == NULL) || (arg == NULL) ||
3993 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3994 xmlXPathFreeObject(arg);
3995 xmlXPathFreeObject(s);
3996 return(0);
3997 }
3998 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003999 if (ns != NULL) {
4000 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004001 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004002 if (str2 != NULL) {
4003 valuePush(ctxt,
4004 xmlXPathNewString(str2));
4005 xmlFree(str2);
4006 valuePush(ctxt, xmlXPathObjectCopy(s));
4007 ret = xmlXPathCompareValues(ctxt, inf, strict);
4008 if (ret)
4009 break;
4010 }
4011 }
Owen Taylor3473f882001-02-23 17:55:21 +00004012 }
4013 xmlXPathFreeObject(arg);
4014 xmlXPathFreeObject(s);
4015 return(ret);
4016}
4017
4018/**
4019 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004020 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00004021 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004022 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00004023 * @arg2: the second node set object
4024 *
4025 * Implement the compare operation on nodesets:
4026 *
4027 * If both objects to be compared are node-sets, then the comparison
4028 * will be true if and only if there is a node in the first node-set
4029 * and a node in the second node-set such that the result of performing
4030 * the comparison on the string-values of the two nodes is true.
4031 * ....
4032 * When neither object to be compared is a node-set and the operator
4033 * is <=, <, >= or >, then the objects are compared by converting both
4034 * objects to numbers and comparing the numbers according to IEEE 754.
4035 * ....
4036 * The number function converts its argument to a number as follows:
4037 * - a string that consists of optional whitespace followed by an
4038 * optional minus sign followed by a Number followed by whitespace
4039 * is converted to the IEEE 754 number that is nearest (according
4040 * to the IEEE 754 round-to-nearest rule) to the mathematical value
4041 * represented by the string; any other string is converted to NaN
4042 *
4043 * Conclusion all nodes need to be converted first to their string value
4044 * and then the comparison must be done when possible
4045 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004046static int
4047xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00004048 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4049 int i, j, init = 0;
4050 double val1;
4051 double *values2;
4052 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004053 xmlNodeSetPtr ns1;
4054 xmlNodeSetPtr ns2;
4055
4056 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004057 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4058 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004059 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004060 }
Owen Taylor3473f882001-02-23 17:55:21 +00004061 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004062 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4063 xmlXPathFreeObject(arg1);
4064 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004065 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004066 }
Owen Taylor3473f882001-02-23 17:55:21 +00004067
4068 ns1 = arg1->nodesetval;
4069 ns2 = arg2->nodesetval;
4070
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004071 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004072 xmlXPathFreeObject(arg1);
4073 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004074 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004075 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004076 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004077 xmlXPathFreeObject(arg1);
4078 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004079 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004080 }
Owen Taylor3473f882001-02-23 17:55:21 +00004081
4082 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4083 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004084 xmlXPathFreeObject(arg1);
4085 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004086 return(0);
4087 }
4088 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004089 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004090 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004091 continue;
4092 for (j = 0;j < ns2->nodeNr;j++) {
4093 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004094 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004095 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004096 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004097 continue;
4098 if (inf && strict)
4099 ret = (val1 < values2[j]);
4100 else if (inf && !strict)
4101 ret = (val1 <= values2[j]);
4102 else if (!inf && strict)
4103 ret = (val1 > values2[j]);
4104 else if (!inf && !strict)
4105 ret = (val1 >= values2[j]);
4106 if (ret)
4107 break;
4108 }
4109 if (ret)
4110 break;
4111 init = 1;
4112 }
4113 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004114 xmlXPathFreeObject(arg1);
4115 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004116 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004117}
4118
4119/**
4120 * xmlXPathCompareNodeSetValue:
4121 * @ctxt: the XPath Parser context
4122 * @inf: less than (1) or greater than (0)
4123 * @strict: is the comparison strict
4124 * @arg: the node set
4125 * @val: the value
4126 *
4127 * Implement the compare operation between a nodeset and a value
4128 * @ns < @val (1, 1, ...
4129 * @ns <= @val (1, 0, ...
4130 * @ns > @val (0, 1, ...
4131 * @ns >= @val (0, 0, ...
4132 *
4133 * If one object to be compared is a node-set and the other is a boolean,
4134 * then the comparison will be true if and only if the result of performing
4135 * the comparison on the boolean and on the result of converting
4136 * the node-set to a boolean using the boolean function is true.
4137 *
4138 * Returns 0 or 1 depending on the results of the test.
4139 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004140static int
Owen Taylor3473f882001-02-23 17:55:21 +00004141xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4142 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4143 if ((val == NULL) || (arg == NULL) ||
4144 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4145 return(0);
4146
4147 switch(val->type) {
4148 case XPATH_NUMBER:
4149 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4150 case XPATH_NODESET:
4151 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004152 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004153 case XPATH_STRING:
4154 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4155 case XPATH_BOOLEAN:
4156 valuePush(ctxt, arg);
4157 xmlXPathBooleanFunction(ctxt, 1);
4158 valuePush(ctxt, val);
4159 return(xmlXPathCompareValues(ctxt, inf, strict));
4160 default:
4161 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004162 }
4163 return(0);
4164}
4165
4166/**
4167 * xmlXPathEqualNodeSetString
4168 * @arg: the nodeset object argument
4169 * @str: the string to compare to.
4170 *
4171 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4172 * If one object to be compared is a node-set and the other is a string,
4173 * then the comparison will be true if and only if there is a node in
4174 * the node-set such that the result of performing the comparison on the
4175 * string-value of the node and the other string is true.
4176 *
4177 * Returns 0 or 1 depending on the results of the test.
4178 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004179static int
Daniel Veillardf06307e2001-07-03 10:35:50 +00004180xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str)
4181{
Owen Taylor3473f882001-02-23 17:55:21 +00004182 int i;
4183 xmlNodeSetPtr ns;
4184 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004185 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004186
4187 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004188 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4189 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004190 ns = arg->nodesetval;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004191 hash = xmlXPathStringHash(str);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004192 if (ns == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004193 return (0);
Daniel Veillard73c9c042001-07-05 20:02:54 +00004194 if (ns->nodeNr <= 0) {
4195 if (hash == 0)
4196 return(1);
4197 return(0);
4198 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004199 for (i = 0; i < ns->nodeNr; i++) {
4200 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4201 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4202 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4203 xmlFree(str2);
4204 return (1);
4205 }
4206 if (str2 != NULL)
4207 xmlFree(str2);
4208 }
Owen Taylor3473f882001-02-23 17:55:21 +00004209 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004210 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004211}
4212
4213/**
4214 * xmlXPathEqualNodeSetFloat
4215 * @arg: the nodeset object argument
4216 * @f: the float to compare to
4217 *
4218 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4219 * If one object to be compared is a node-set and the other is a number,
4220 * then the comparison will be true if and only if there is a node in
4221 * the node-set such that the result of performing the comparison on the
4222 * number to be compared and on the result of converting the string-value
4223 * of that node to a number using the number function is true.
4224 *
4225 * Returns 0 or 1 depending on the results of the test.
4226 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004227static int
Owen Taylor3473f882001-02-23 17:55:21 +00004228xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, double f) {
4229 char buf[100] = "";
4230
4231 if ((arg == NULL) ||
4232 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4233 return(0);
4234
Bjorn Reesee1dc0112001-03-03 12:09:03 +00004235 xmlXPathFormatNumber(f, buf, sizeof(buf));
Owen Taylor3473f882001-02-23 17:55:21 +00004236 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
4237}
4238
4239
4240/**
4241 * xmlXPathEqualNodeSets
4242 * @arg1: first nodeset object argument
4243 * @arg2: second nodeset object argument
4244 *
4245 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
4246 * If both objects to be compared are node-sets, then the comparison
4247 * will be true if and only if there is a node in the first node-set and
4248 * a node in the second node-set such that the result of performing the
4249 * comparison on the string-values of the two nodes is true.
4250 *
4251 * (needless to say, this is a costly operation)
4252 *
4253 * Returns 0 or 1 depending on the results of the test.
4254 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004255static int
Owen Taylor3473f882001-02-23 17:55:21 +00004256xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4257 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004258 unsigned int *hashs1;
4259 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004260 xmlChar **values1;
4261 xmlChar **values2;
4262 int ret = 0;
4263 xmlNodeSetPtr ns1;
4264 xmlNodeSetPtr ns2;
4265
4266 if ((arg1 == NULL) ||
4267 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4268 return(0);
4269 if ((arg2 == NULL) ||
4270 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4271 return(0);
4272
4273 ns1 = arg1->nodesetval;
4274 ns2 = arg2->nodesetval;
4275
Daniel Veillard911f49a2001-04-07 15:39:35 +00004276 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004277 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004278 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004279 return(0);
4280
4281 /*
4282 * check if there is a node pertaining to both sets
4283 */
4284 for (i = 0;i < ns1->nodeNr;i++)
4285 for (j = 0;j < ns2->nodeNr;j++)
4286 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4287 return(1);
4288
4289 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
4290 if (values1 == NULL)
4291 return(0);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004292 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4293 if (hashs1 == NULL) {
4294 xmlFree(values1);
4295 return(0);
4296 }
Owen Taylor3473f882001-02-23 17:55:21 +00004297 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4298 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4299 if (values2 == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004300 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004301 xmlFree(values1);
4302 return(0);
4303 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004304 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4305 if (hashs2 == NULL) {
4306 xmlFree(hashs1);
4307 xmlFree(values1);
4308 xmlFree(values2);
4309 return(0);
4310 }
Owen Taylor3473f882001-02-23 17:55:21 +00004311 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4312 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004313 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004314 for (j = 0;j < ns2->nodeNr;j++) {
4315 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004316 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
4317 if (hashs1[i] == hashs2[j]) {
4318 if (values1[i] == NULL)
4319 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4320 if (values2[j] == NULL)
4321 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
4322 ret = xmlStrEqual(values1[i], values2[j]);
4323 if (ret)
4324 break;
4325 }
Owen Taylor3473f882001-02-23 17:55:21 +00004326 }
4327 if (ret)
4328 break;
4329 }
4330 for (i = 0;i < ns1->nodeNr;i++)
4331 if (values1[i] != NULL)
4332 xmlFree(values1[i]);
4333 for (j = 0;j < ns2->nodeNr;j++)
4334 if (values2[j] != NULL)
4335 xmlFree(values2[j]);
4336 xmlFree(values1);
4337 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004338 xmlFree(hashs1);
4339 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004340 return(ret);
4341}
4342
4343/**
4344 * xmlXPathEqualValues:
4345 * @ctxt: the XPath Parser context
4346 *
4347 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4348 *
4349 * Returns 0 or 1 depending on the results of the test.
4350 */
4351int
4352xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4353 xmlXPathObjectPtr arg1, arg2;
4354 int ret = 0;
4355
4356 arg1 = valuePop(ctxt);
4357 if (arg1 == NULL)
4358 XP_ERROR0(XPATH_INVALID_OPERAND);
4359
4360 arg2 = valuePop(ctxt);
4361 if (arg2 == NULL) {
4362 xmlXPathFreeObject(arg1);
4363 XP_ERROR0(XPATH_INVALID_OPERAND);
4364 }
4365
4366 if (arg1 == arg2) {
4367#ifdef DEBUG_EXPR
4368 xmlGenericError(xmlGenericErrorContext,
4369 "Equal: by pointer\n");
4370#endif
4371 return(1);
4372 }
4373
4374 switch (arg1->type) {
4375 case XPATH_UNDEFINED:
4376#ifdef DEBUG_EXPR
4377 xmlGenericError(xmlGenericErrorContext,
4378 "Equal: undefined\n");
4379#endif
4380 break;
4381 case XPATH_XSLT_TREE:
4382 case XPATH_NODESET:
4383 switch (arg2->type) {
4384 case XPATH_UNDEFINED:
4385#ifdef DEBUG_EXPR
4386 xmlGenericError(xmlGenericErrorContext,
4387 "Equal: undefined\n");
4388#endif
4389 break;
4390 case XPATH_XSLT_TREE:
4391 case XPATH_NODESET:
4392 ret = xmlXPathEqualNodeSets(arg1, arg2);
4393 break;
4394 case XPATH_BOOLEAN:
4395 if ((arg1->nodesetval == NULL) ||
4396 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4397 else
4398 ret = 1;
4399 ret = (ret == arg2->boolval);
4400 break;
4401 case XPATH_NUMBER:
4402 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
4403 break;
4404 case XPATH_STRING:
4405 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
4406 break;
4407 case XPATH_USERS:
4408 case XPATH_POINT:
4409 case XPATH_RANGE:
4410 case XPATH_LOCATIONSET:
4411 TODO
4412 break;
4413 }
4414 break;
4415 case XPATH_BOOLEAN:
4416 switch (arg2->type) {
4417 case XPATH_UNDEFINED:
4418#ifdef DEBUG_EXPR
4419 xmlGenericError(xmlGenericErrorContext,
4420 "Equal: undefined\n");
4421#endif
4422 break;
4423 case XPATH_NODESET:
4424 case XPATH_XSLT_TREE:
4425 if ((arg2->nodesetval == NULL) ||
Daniel Veillardbd6e6312002-04-01 08:04:14 +00004426 (arg2->nodesetval->nodeNr == 0))
4427 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004428 else
4429 ret = 1;
Daniel Veillardbd6e6312002-04-01 08:04:14 +00004430 ret = (ret == arg1->boolval);
Owen Taylor3473f882001-02-23 17:55:21 +00004431 break;
4432 case XPATH_BOOLEAN:
4433#ifdef DEBUG_EXPR
4434 xmlGenericError(xmlGenericErrorContext,
4435 "Equal: %d boolean %d \n",
4436 arg1->boolval, arg2->boolval);
4437#endif
4438 ret = (arg1->boolval == arg2->boolval);
4439 break;
4440 case XPATH_NUMBER:
4441 if (arg2->floatval) ret = 1;
4442 else ret = 0;
4443 ret = (arg1->boolval == ret);
4444 break;
4445 case XPATH_STRING:
4446 if ((arg2->stringval == NULL) ||
4447 (arg2->stringval[0] == 0)) ret = 0;
4448 else
4449 ret = 1;
4450 ret = (arg1->boolval == ret);
4451 break;
4452 case XPATH_USERS:
4453 case XPATH_POINT:
4454 case XPATH_RANGE:
4455 case XPATH_LOCATIONSET:
4456 TODO
4457 break;
4458 }
4459 break;
4460 case XPATH_NUMBER:
4461 switch (arg2->type) {
4462 case XPATH_UNDEFINED:
4463#ifdef DEBUG_EXPR
4464 xmlGenericError(xmlGenericErrorContext,
4465 "Equal: undefined\n");
4466#endif
4467 break;
4468 case XPATH_NODESET:
4469 case XPATH_XSLT_TREE:
4470 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
4471 break;
4472 case XPATH_BOOLEAN:
4473 if (arg1->floatval) ret = 1;
4474 else ret = 0;
4475 ret = (arg2->boolval == ret);
4476 break;
4477 case XPATH_STRING:
4478 valuePush(ctxt, arg2);
4479 xmlXPathNumberFunction(ctxt, 1);
4480 arg2 = valuePop(ctxt);
4481 /* no break on purpose */
4482 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004483 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004484 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4485 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004486 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4487 if (xmlXPathIsInf(arg2->floatval) == 1)
4488 ret = 1;
4489 else
4490 ret = 0;
4491 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4492 if (xmlXPathIsInf(arg2->floatval) == -1)
4493 ret = 1;
4494 else
4495 ret = 0;
4496 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4497 if (xmlXPathIsInf(arg1->floatval) == 1)
4498 ret = 1;
4499 else
4500 ret = 0;
4501 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4502 if (xmlXPathIsInf(arg1->floatval) == -1)
4503 ret = 1;
4504 else
4505 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004506 } else {
4507 ret = (arg1->floatval == arg2->floatval);
4508 }
Owen Taylor3473f882001-02-23 17:55:21 +00004509 break;
4510 case XPATH_USERS:
4511 case XPATH_POINT:
4512 case XPATH_RANGE:
4513 case XPATH_LOCATIONSET:
4514 TODO
4515 break;
4516 }
4517 break;
4518 case XPATH_STRING:
4519 switch (arg2->type) {
4520 case XPATH_UNDEFINED:
4521#ifdef DEBUG_EXPR
4522 xmlGenericError(xmlGenericErrorContext,
4523 "Equal: undefined\n");
4524#endif
4525 break;
4526 case XPATH_NODESET:
4527 case XPATH_XSLT_TREE:
4528 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
4529 break;
4530 case XPATH_BOOLEAN:
4531 if ((arg1->stringval == NULL) ||
4532 (arg1->stringval[0] == 0)) ret = 0;
4533 else
4534 ret = 1;
4535 ret = (arg2->boolval == ret);
4536 break;
4537 case XPATH_STRING:
4538 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4539 break;
4540 case XPATH_NUMBER:
4541 valuePush(ctxt, arg1);
4542 xmlXPathNumberFunction(ctxt, 1);
4543 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004544 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004545 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4546 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004547 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4548 if (xmlXPathIsInf(arg2->floatval) == 1)
4549 ret = 1;
4550 else
4551 ret = 0;
4552 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4553 if (xmlXPathIsInf(arg2->floatval) == -1)
4554 ret = 1;
4555 else
4556 ret = 0;
4557 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4558 if (xmlXPathIsInf(arg1->floatval) == 1)
4559 ret = 1;
4560 else
4561 ret = 0;
4562 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4563 if (xmlXPathIsInf(arg1->floatval) == -1)
4564 ret = 1;
4565 else
4566 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004567 } else {
4568 ret = (arg1->floatval == arg2->floatval);
4569 }
Owen Taylor3473f882001-02-23 17:55:21 +00004570 break;
4571 case XPATH_USERS:
4572 case XPATH_POINT:
4573 case XPATH_RANGE:
4574 case XPATH_LOCATIONSET:
4575 TODO
4576 break;
4577 }
4578 break;
4579 case XPATH_USERS:
4580 case XPATH_POINT:
4581 case XPATH_RANGE:
4582 case XPATH_LOCATIONSET:
4583 TODO
4584 break;
4585 }
4586 xmlXPathFreeObject(arg1);
4587 xmlXPathFreeObject(arg2);
4588 return(ret);
4589}
4590
4591
4592/**
4593 * xmlXPathCompareValues:
4594 * @ctxt: the XPath Parser context
4595 * @inf: less than (1) or greater than (0)
4596 * @strict: is the comparison strict
4597 *
4598 * Implement the compare operation on XPath objects:
4599 * @arg1 < @arg2 (1, 1, ...
4600 * @arg1 <= @arg2 (1, 0, ...
4601 * @arg1 > @arg2 (0, 1, ...
4602 * @arg1 >= @arg2 (0, 0, ...
4603 *
4604 * When neither object to be compared is a node-set and the operator is
4605 * <=, <, >=, >, then the objects are compared by converted both objects
4606 * to numbers and comparing the numbers according to IEEE 754. The <
4607 * comparison will be true if and only if the first number is less than the
4608 * second number. The <= comparison will be true if and only if the first
4609 * number is less than or equal to the second number. The > comparison
4610 * will be true if and only if the first number is greater than the second
4611 * number. The >= comparison will be true if and only if the first number
4612 * is greater than or equal to the second number.
4613 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004614 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00004615 */
4616int
4617xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004618 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004619 xmlXPathObjectPtr arg1, arg2;
4620
4621 arg2 = valuePop(ctxt);
4622 if (arg2 == NULL) {
4623 XP_ERROR0(XPATH_INVALID_OPERAND);
4624 }
4625
4626 arg1 = valuePop(ctxt);
4627 if (arg1 == NULL) {
4628 xmlXPathFreeObject(arg2);
4629 XP_ERROR0(XPATH_INVALID_OPERAND);
4630 }
4631
4632 if ((arg2->type == XPATH_NODESET) || (arg1->type == XPATH_NODESET)) {
4633 if ((arg2->type == XPATH_NODESET) && (arg1->type == XPATH_NODESET)) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004634 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004635 } else {
4636 if (arg1->type == XPATH_NODESET) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004637 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
4638 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004639 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004640 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
4641 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00004642 }
4643 }
4644 return(ret);
4645 }
4646
4647 if (arg1->type != XPATH_NUMBER) {
4648 valuePush(ctxt, arg1);
4649 xmlXPathNumberFunction(ctxt, 1);
4650 arg1 = valuePop(ctxt);
4651 }
4652 if (arg1->type != XPATH_NUMBER) {
4653 xmlXPathFreeObject(arg1);
4654 xmlXPathFreeObject(arg2);
4655 XP_ERROR0(XPATH_INVALID_OPERAND);
4656 }
4657 if (arg2->type != XPATH_NUMBER) {
4658 valuePush(ctxt, arg2);
4659 xmlXPathNumberFunction(ctxt, 1);
4660 arg2 = valuePop(ctxt);
4661 }
4662 if (arg2->type != XPATH_NUMBER) {
4663 xmlXPathFreeObject(arg1);
4664 xmlXPathFreeObject(arg2);
4665 XP_ERROR0(XPATH_INVALID_OPERAND);
4666 }
4667 /*
4668 * Add tests for infinity and nan
4669 * => feedback on 3.4 for Inf and NaN
4670 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004671 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00004672 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004673 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004674 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004675 arg1i=xmlXPathIsInf(arg1->floatval);
4676 arg2i=xmlXPathIsInf(arg2->floatval);
4677 if (inf && strict) {
4678 if ((arg1i == -1 && arg2i != -1) ||
4679 (arg2i == 1 && arg1i != 1)) {
4680 ret = 1;
4681 } else if (arg1i == 0 && arg2i == 0) {
4682 ret = (arg1->floatval < arg2->floatval);
4683 } else {
4684 ret = 0;
4685 }
4686 }
4687 else if (inf && !strict) {
4688 if (arg1i == -1 || arg2i == 1) {
4689 ret = 1;
4690 } else if (arg1i == 0 && arg2i == 0) {
4691 ret = (arg1->floatval <= arg2->floatval);
4692 } else {
4693 ret = 0;
4694 }
4695 }
4696 else if (!inf && strict) {
4697 if ((arg1i == 1 && arg2i != 1) ||
4698 (arg2i == -1 && arg1i != -1)) {
4699 ret = 1;
4700 } else if (arg1i == 0 && arg2i == 0) {
4701 ret = (arg1->floatval > arg2->floatval);
4702 } else {
4703 ret = 0;
4704 }
4705 }
4706 else if (!inf && !strict) {
4707 if (arg1i == 1 || arg2i == -1) {
4708 ret = 1;
4709 } else if (arg1i == 0 && arg2i == 0) {
4710 ret = (arg1->floatval >= arg2->floatval);
4711 } else {
4712 ret = 0;
4713 }
4714 }
Daniel Veillard21458c82002-03-27 16:12:22 +00004715 }
Owen Taylor3473f882001-02-23 17:55:21 +00004716 xmlXPathFreeObject(arg1);
4717 xmlXPathFreeObject(arg2);
4718 return(ret);
4719}
4720
4721/**
4722 * xmlXPathValueFlipSign:
4723 * @ctxt: the XPath Parser context
4724 *
4725 * Implement the unary - operation on an XPath object
4726 * The numeric operators convert their operands to numbers as if
4727 * by calling the number function.
4728 */
4729void
4730xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004731 CAST_TO_NUMBER;
4732 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00004733 if (ctxt->value->floatval == 0) {
4734 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
4735 ctxt->value->floatval = xmlXPathNZERO;
4736 else
4737 ctxt->value->floatval = 0;
4738 }
4739 else
4740 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00004741}
4742
4743/**
4744 * xmlXPathAddValues:
4745 * @ctxt: the XPath Parser context
4746 *
4747 * Implement the add operation on XPath objects:
4748 * The numeric operators convert their operands to numbers as if
4749 * by calling the number function.
4750 */
4751void
4752xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
4753 xmlXPathObjectPtr arg;
4754 double val;
4755
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004756 arg = valuePop(ctxt);
4757 if (arg == NULL)
4758 XP_ERROR(XPATH_INVALID_OPERAND);
4759 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004760 xmlXPathFreeObject(arg);
4761
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004762 CAST_TO_NUMBER;
4763 CHECK_TYPE(XPATH_NUMBER);
4764 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00004765}
4766
4767/**
4768 * xmlXPathSubValues:
4769 * @ctxt: the XPath Parser context
4770 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004771 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00004772 * The numeric operators convert their operands to numbers as if
4773 * by calling the number function.
4774 */
4775void
4776xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
4777 xmlXPathObjectPtr arg;
4778 double val;
4779
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004780 arg = valuePop(ctxt);
4781 if (arg == NULL)
4782 XP_ERROR(XPATH_INVALID_OPERAND);
4783 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004784 xmlXPathFreeObject(arg);
4785
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004786 CAST_TO_NUMBER;
4787 CHECK_TYPE(XPATH_NUMBER);
4788 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004789}
4790
4791/**
4792 * xmlXPathMultValues:
4793 * @ctxt: the XPath Parser context
4794 *
4795 * Implement the multiply operation on XPath objects:
4796 * The numeric operators convert their operands to numbers as if
4797 * by calling the number function.
4798 */
4799void
4800xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
4801 xmlXPathObjectPtr arg;
4802 double val;
4803
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004804 arg = valuePop(ctxt);
4805 if (arg == NULL)
4806 XP_ERROR(XPATH_INVALID_OPERAND);
4807 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004808 xmlXPathFreeObject(arg);
4809
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004810 CAST_TO_NUMBER;
4811 CHECK_TYPE(XPATH_NUMBER);
4812 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004813}
4814
4815/**
4816 * xmlXPathDivValues:
4817 * @ctxt: the XPath Parser context
4818 *
4819 * Implement the div operation on XPath objects @arg1 / @arg2:
4820 * The numeric operators convert their operands to numbers as if
4821 * by calling the number function.
4822 */
4823void
4824xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
4825 xmlXPathObjectPtr arg;
4826 double val;
4827
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004828 arg = valuePop(ctxt);
4829 if (arg == NULL)
4830 XP_ERROR(XPATH_INVALID_OPERAND);
4831 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004832 xmlXPathFreeObject(arg);
4833
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004834 CAST_TO_NUMBER;
4835 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004836 if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00004837 if (ctxt->value->floatval == 0)
4838 ctxt->value->floatval = xmlXPathNAN;
4839 else if (ctxt->value->floatval > 0)
4840 ctxt->value->floatval = xmlXPathNINF;
4841 else if (ctxt->value->floatval < 0)
4842 ctxt->value->floatval = xmlXPathPINF;
4843 }
4844 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00004845 if (ctxt->value->floatval == 0)
4846 ctxt->value->floatval = xmlXPathNAN;
4847 else if (ctxt->value->floatval > 0)
4848 ctxt->value->floatval = xmlXPathPINF;
4849 else if (ctxt->value->floatval < 0)
4850 ctxt->value->floatval = xmlXPathNINF;
4851 } else
4852 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004853}
4854
4855/**
4856 * xmlXPathModValues:
4857 * @ctxt: the XPath Parser context
4858 *
4859 * Implement the mod operation on XPath objects: @arg1 / @arg2
4860 * The numeric operators convert their operands to numbers as if
4861 * by calling the number function.
4862 */
4863void
4864xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
4865 xmlXPathObjectPtr arg;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00004866 double arg1, arg2, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00004867
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004868 arg = valuePop(ctxt);
4869 if (arg == NULL)
4870 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00004871 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004872 xmlXPathFreeObject(arg);
4873
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004874 CAST_TO_NUMBER;
4875 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00004876 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00004877 if (arg2 == 0)
4878 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00004879 else {
4880 tmp=arg1/arg2;
4881 ctxt->value->floatval = arg2 * (tmp - (double)((int)tmp));
4882 }
Owen Taylor3473f882001-02-23 17:55:21 +00004883}
4884
4885/************************************************************************
4886 * *
4887 * The traversal functions *
4888 * *
4889 ************************************************************************/
4890
Owen Taylor3473f882001-02-23 17:55:21 +00004891/*
4892 * A traversal function enumerates nodes along an axis.
4893 * Initially it must be called with NULL, and it indicates
4894 * termination on the axis by returning NULL.
4895 */
4896typedef xmlNodePtr (*xmlXPathTraversalFunction)
4897 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
4898
4899/**
4900 * xmlXPathNextSelf:
4901 * @ctxt: the XPath Parser context
4902 * @cur: the current node in the traversal
4903 *
4904 * Traversal function for the "self" direction
4905 * The self axis contains just the context node itself
4906 *
4907 * Returns the next element following that axis
4908 */
4909xmlNodePtr
4910xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4911 if (cur == NULL)
4912 return(ctxt->context->node);
4913 return(NULL);
4914}
4915
4916/**
4917 * xmlXPathNextChild:
4918 * @ctxt: the XPath Parser context
4919 * @cur: the current node in the traversal
4920 *
4921 * Traversal function for the "child" direction
4922 * The child axis contains the children of the context node in document order.
4923 *
4924 * Returns the next element following that axis
4925 */
4926xmlNodePtr
4927xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4928 if (cur == NULL) {
4929 if (ctxt->context->node == NULL) return(NULL);
4930 switch (ctxt->context->node->type) {
4931 case XML_ELEMENT_NODE:
4932 case XML_TEXT_NODE:
4933 case XML_CDATA_SECTION_NODE:
4934 case XML_ENTITY_REF_NODE:
4935 case XML_ENTITY_NODE:
4936 case XML_PI_NODE:
4937 case XML_COMMENT_NODE:
4938 case XML_NOTATION_NODE:
4939 case XML_DTD_NODE:
4940 return(ctxt->context->node->children);
4941 case XML_DOCUMENT_NODE:
4942 case XML_DOCUMENT_TYPE_NODE:
4943 case XML_DOCUMENT_FRAG_NODE:
4944 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004945#ifdef LIBXML_DOCB_ENABLED
4946 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004947#endif
4948 return(((xmlDocPtr) ctxt->context->node)->children);
4949 case XML_ELEMENT_DECL:
4950 case XML_ATTRIBUTE_DECL:
4951 case XML_ENTITY_DECL:
4952 case XML_ATTRIBUTE_NODE:
4953 case XML_NAMESPACE_DECL:
4954 case XML_XINCLUDE_START:
4955 case XML_XINCLUDE_END:
4956 return(NULL);
4957 }
4958 return(NULL);
4959 }
4960 if ((cur->type == XML_DOCUMENT_NODE) ||
4961 (cur->type == XML_HTML_DOCUMENT_NODE))
4962 return(NULL);
4963 return(cur->next);
4964}
4965
4966/**
4967 * xmlXPathNextDescendant:
4968 * @ctxt: the XPath Parser context
4969 * @cur: the current node in the traversal
4970 *
4971 * Traversal function for the "descendant" direction
4972 * the descendant axis contains the descendants of the context node in document
4973 * order; a descendant is a child or a child of a child and so on.
4974 *
4975 * Returns the next element following that axis
4976 */
4977xmlNodePtr
4978xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4979 if (cur == NULL) {
4980 if (ctxt->context->node == NULL)
4981 return(NULL);
4982 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4983 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4984 return(NULL);
4985
4986 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
4987 return(ctxt->context->doc->children);
4988 return(ctxt->context->node->children);
4989 }
4990
Daniel Veillard567e1b42001-08-01 15:53:47 +00004991 if (cur->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004992 if (cur->children->type != XML_ENTITY_DECL)
Daniel Veillard567e1b42001-08-01 15:53:47 +00004993 return(cur->children);
4994 }
4995
4996 if (cur == ctxt->context->node) return(NULL);
4997
Owen Taylor3473f882001-02-23 17:55:21 +00004998 if (cur->next != NULL) return(cur->next);
4999
5000 do {
5001 cur = cur->parent;
5002 if (cur == NULL) return(NULL);
5003 if (cur == ctxt->context->node) return(NULL);
5004 if (cur->next != NULL) {
5005 cur = cur->next;
5006 return(cur);
5007 }
5008 } while (cur != NULL);
5009 return(cur);
5010}
5011
5012/**
5013 * xmlXPathNextDescendantOrSelf:
5014 * @ctxt: the XPath Parser context
5015 * @cur: the current node in the traversal
5016 *
5017 * Traversal function for the "descendant-or-self" direction
5018 * the descendant-or-self axis contains the context node and the descendants
5019 * of the context node in document order; thus the context node is the first
5020 * node on the axis, and the first child of the context node is the second node
5021 * on the axis
5022 *
5023 * Returns the next element following that axis
5024 */
5025xmlNodePtr
5026xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5027 if (cur == NULL) {
5028 if (ctxt->context->node == NULL)
5029 return(NULL);
5030 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5031 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5032 return(NULL);
5033 return(ctxt->context->node);
5034 }
5035
5036 return(xmlXPathNextDescendant(ctxt, cur));
5037}
5038
5039/**
5040 * xmlXPathNextParent:
5041 * @ctxt: the XPath Parser context
5042 * @cur: the current node in the traversal
5043 *
5044 * Traversal function for the "parent" direction
5045 * The parent axis contains the parent of the context node, if there is one.
5046 *
5047 * Returns the next element following that axis
5048 */
5049xmlNodePtr
5050xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5051 /*
5052 * the parent of an attribute or namespace node is the element
5053 * to which the attribute or namespace node is attached
5054 * Namespace handling !!!
5055 */
5056 if (cur == NULL) {
5057 if (ctxt->context->node == NULL) return(NULL);
5058 switch (ctxt->context->node->type) {
5059 case XML_ELEMENT_NODE:
5060 case XML_TEXT_NODE:
5061 case XML_CDATA_SECTION_NODE:
5062 case XML_ENTITY_REF_NODE:
5063 case XML_ENTITY_NODE:
5064 case XML_PI_NODE:
5065 case XML_COMMENT_NODE:
5066 case XML_NOTATION_NODE:
5067 case XML_DTD_NODE:
5068 case XML_ELEMENT_DECL:
5069 case XML_ATTRIBUTE_DECL:
5070 case XML_XINCLUDE_START:
5071 case XML_XINCLUDE_END:
5072 case XML_ENTITY_DECL:
5073 if (ctxt->context->node->parent == NULL)
5074 return((xmlNodePtr) ctxt->context->doc);
5075 return(ctxt->context->node->parent);
5076 case XML_ATTRIBUTE_NODE: {
5077 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5078
5079 return(att->parent);
5080 }
5081 case XML_DOCUMENT_NODE:
5082 case XML_DOCUMENT_TYPE_NODE:
5083 case XML_DOCUMENT_FRAG_NODE:
5084 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005085#ifdef LIBXML_DOCB_ENABLED
5086 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005087#endif
5088 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005089 case XML_NAMESPACE_DECL: {
5090 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5091
5092 if ((ns->next != NULL) &&
5093 (ns->next->type != XML_NAMESPACE_DECL))
5094 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005095 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005096 }
Owen Taylor3473f882001-02-23 17:55:21 +00005097 }
5098 }
5099 return(NULL);
5100}
5101
5102/**
5103 * xmlXPathNextAncestor:
5104 * @ctxt: the XPath Parser context
5105 * @cur: the current node in the traversal
5106 *
5107 * Traversal function for the "ancestor" direction
5108 * the ancestor axis contains the ancestors of the context node; the ancestors
5109 * of the context node consist of the parent of context node and the parent's
5110 * parent and so on; the nodes are ordered in reverse document order; thus the
5111 * parent is the first node on the axis, and the parent's parent is the second
5112 * node on the axis
5113 *
5114 * Returns the next element following that axis
5115 */
5116xmlNodePtr
5117xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5118 /*
5119 * the parent of an attribute or namespace node is the element
5120 * to which the attribute or namespace node is attached
5121 * !!!!!!!!!!!!!
5122 */
5123 if (cur == NULL) {
5124 if (ctxt->context->node == NULL) return(NULL);
5125 switch (ctxt->context->node->type) {
5126 case XML_ELEMENT_NODE:
5127 case XML_TEXT_NODE:
5128 case XML_CDATA_SECTION_NODE:
5129 case XML_ENTITY_REF_NODE:
5130 case XML_ENTITY_NODE:
5131 case XML_PI_NODE:
5132 case XML_COMMENT_NODE:
5133 case XML_DTD_NODE:
5134 case XML_ELEMENT_DECL:
5135 case XML_ATTRIBUTE_DECL:
5136 case XML_ENTITY_DECL:
5137 case XML_NOTATION_NODE:
5138 case XML_XINCLUDE_START:
5139 case XML_XINCLUDE_END:
5140 if (ctxt->context->node->parent == NULL)
5141 return((xmlNodePtr) ctxt->context->doc);
5142 return(ctxt->context->node->parent);
5143 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005144 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005145
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005146 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005147 }
5148 case XML_DOCUMENT_NODE:
5149 case XML_DOCUMENT_TYPE_NODE:
5150 case XML_DOCUMENT_FRAG_NODE:
5151 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005152#ifdef LIBXML_DOCB_ENABLED
5153 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005154#endif
5155 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005156 case XML_NAMESPACE_DECL: {
5157 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5158
5159 if ((ns->next != NULL) &&
5160 (ns->next->type != XML_NAMESPACE_DECL))
5161 return((xmlNodePtr) ns->next);
5162 /* Bad, how did that namespace ended-up there ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005163 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005164 }
Owen Taylor3473f882001-02-23 17:55:21 +00005165 }
5166 return(NULL);
5167 }
5168 if (cur == ctxt->context->doc->children)
5169 return((xmlNodePtr) ctxt->context->doc);
5170 if (cur == (xmlNodePtr) ctxt->context->doc)
5171 return(NULL);
5172 switch (cur->type) {
5173 case XML_ELEMENT_NODE:
5174 case XML_TEXT_NODE:
5175 case XML_CDATA_SECTION_NODE:
5176 case XML_ENTITY_REF_NODE:
5177 case XML_ENTITY_NODE:
5178 case XML_PI_NODE:
5179 case XML_COMMENT_NODE:
5180 case XML_NOTATION_NODE:
5181 case XML_DTD_NODE:
5182 case XML_ELEMENT_DECL:
5183 case XML_ATTRIBUTE_DECL:
5184 case XML_ENTITY_DECL:
5185 case XML_XINCLUDE_START:
5186 case XML_XINCLUDE_END:
5187 return(cur->parent);
5188 case XML_ATTRIBUTE_NODE: {
5189 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5190
5191 return(att->parent);
5192 }
5193 case XML_DOCUMENT_NODE:
5194 case XML_DOCUMENT_TYPE_NODE:
5195 case XML_DOCUMENT_FRAG_NODE:
5196 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005197#ifdef LIBXML_DOCB_ENABLED
5198 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005199#endif
5200 return(NULL);
5201 case XML_NAMESPACE_DECL:
5202 /*
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005203 * this should not hapen a namespace can't be
5204 * the ancestor of another node
Owen Taylor3473f882001-02-23 17:55:21 +00005205 */
5206 return(NULL);
5207 }
5208 return(NULL);
5209}
5210
5211/**
5212 * xmlXPathNextAncestorOrSelf:
5213 * @ctxt: the XPath Parser context
5214 * @cur: the current node in the traversal
5215 *
5216 * Traversal function for the "ancestor-or-self" direction
5217 * he ancestor-or-self axis contains the context node and ancestors of
5218 * the context node in reverse document order; thus the context node is
5219 * the first node on the axis, and the context node's parent the second;
5220 * parent here is defined the same as with the parent axis.
5221 *
5222 * Returns the next element following that axis
5223 */
5224xmlNodePtr
5225xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5226 if (cur == NULL)
5227 return(ctxt->context->node);
5228 return(xmlXPathNextAncestor(ctxt, cur));
5229}
5230
5231/**
5232 * xmlXPathNextFollowingSibling:
5233 * @ctxt: the XPath Parser context
5234 * @cur: the current node in the traversal
5235 *
5236 * Traversal function for the "following-sibling" direction
5237 * The following-sibling axis contains the following siblings of the context
5238 * node in document order.
5239 *
5240 * Returns the next element following that axis
5241 */
5242xmlNodePtr
5243xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5244 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5245 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5246 return(NULL);
5247 if (cur == (xmlNodePtr) ctxt->context->doc)
5248 return(NULL);
5249 if (cur == NULL)
5250 return(ctxt->context->node->next);
5251 return(cur->next);
5252}
5253
5254/**
5255 * xmlXPathNextPrecedingSibling:
5256 * @ctxt: the XPath Parser context
5257 * @cur: the current node in the traversal
5258 *
5259 * Traversal function for the "preceding-sibling" direction
5260 * The preceding-sibling axis contains the preceding siblings of the context
5261 * node in reverse document order; the first preceding sibling is first on the
5262 * axis; the sibling preceding that node is the second on the axis and so on.
5263 *
5264 * Returns the next element following that axis
5265 */
5266xmlNodePtr
5267xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5268 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5269 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5270 return(NULL);
5271 if (cur == (xmlNodePtr) ctxt->context->doc)
5272 return(NULL);
5273 if (cur == NULL)
5274 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005275 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5276 cur = cur->prev;
5277 if (cur == NULL)
5278 return(ctxt->context->node->prev);
5279 }
Owen Taylor3473f882001-02-23 17:55:21 +00005280 return(cur->prev);
5281}
5282
5283/**
5284 * xmlXPathNextFollowing:
5285 * @ctxt: the XPath Parser context
5286 * @cur: the current node in the traversal
5287 *
5288 * Traversal function for the "following" direction
5289 * The following axis contains all nodes in the same document as the context
5290 * node that are after the context node in document order, excluding any
5291 * descendants and excluding attribute nodes and namespace nodes; the nodes
5292 * are ordered in document order
5293 *
5294 * Returns the next element following that axis
5295 */
5296xmlNodePtr
5297xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5298 if (cur != NULL && cur->children != NULL)
5299 return cur->children ;
5300 if (cur == NULL) cur = ctxt->context->node;
5301 if (cur == NULL) return(NULL) ; /* ERROR */
5302 if (cur->next != NULL) return(cur->next) ;
5303 do {
5304 cur = cur->parent;
5305 if (cur == NULL) return(NULL);
5306 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5307 if (cur->next != NULL) return(cur->next);
5308 } while (cur != NULL);
5309 return(cur);
5310}
5311
5312/*
5313 * xmlXPathIsAncestor:
5314 * @ancestor: the ancestor node
5315 * @node: the current node
5316 *
5317 * Check that @ancestor is a @node's ancestor
5318 *
5319 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5320 */
5321static int
5322xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5323 if ((ancestor == NULL) || (node == NULL)) return(0);
5324 /* nodes need to be in the same document */
5325 if (ancestor->doc != node->doc) return(0);
5326 /* avoid searching if ancestor or node is the root node */
5327 if (ancestor == (xmlNodePtr) node->doc) return(1);
5328 if (node == (xmlNodePtr) ancestor->doc) return(0);
5329 while (node->parent != NULL) {
5330 if (node->parent == ancestor)
5331 return(1);
5332 node = node->parent;
5333 }
5334 return(0);
5335}
5336
5337/**
5338 * xmlXPathNextPreceding:
5339 * @ctxt: the XPath Parser context
5340 * @cur: the current node in the traversal
5341 *
5342 * Traversal function for the "preceding" direction
5343 * the preceding axis contains all nodes in the same document as the context
5344 * node that are before the context node in document order, excluding any
5345 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5346 * ordered in reverse document order
5347 *
5348 * Returns the next element following that axis
5349 */
5350xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005351xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5352{
Owen Taylor3473f882001-02-23 17:55:21 +00005353 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005354 cur = ctxt->context->node;
5355 if (cur == NULL)
5356 return (NULL);
5357 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5358 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005359 do {
5360 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005361 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5362 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005363 }
5364
5365 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005366 if (cur == NULL)
5367 return (NULL);
5368 if (cur == ctxt->context->doc->children)
5369 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005370 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005371 return (cur);
5372}
5373
5374/**
5375 * xmlXPathNextPrecedingInternal:
5376 * @ctxt: the XPath Parser context
5377 * @cur: the current node in the traversal
5378 *
5379 * Traversal function for the "preceding" direction
5380 * the preceding axis contains all nodes in the same document as the context
5381 * node that are before the context node in document order, excluding any
5382 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5383 * ordered in reverse document order
5384 * This is a faster implementation but internal only since it requires a
5385 * state kept in the parser context: ctxt->ancestor.
5386 *
5387 * Returns the next element following that axis
5388 */
5389static xmlNodePtr
5390xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5391 xmlNodePtr cur)
5392{
5393 if (cur == NULL) {
5394 cur = ctxt->context->node;
5395 if (cur == NULL)
5396 return (NULL);
5397 ctxt->ancestor = cur->parent;
5398 }
5399 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5400 cur = cur->prev;
5401 while (cur->prev == NULL) {
5402 cur = cur->parent;
5403 if (cur == NULL)
5404 return (NULL);
5405 if (cur == ctxt->context->doc->children)
5406 return (NULL);
5407 if (cur != ctxt->ancestor)
5408 return (cur);
5409 ctxt->ancestor = cur->parent;
5410 }
5411 cur = cur->prev;
5412 while (cur->last != NULL)
5413 cur = cur->last;
5414 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005415}
5416
5417/**
5418 * xmlXPathNextNamespace:
5419 * @ctxt: the XPath Parser context
5420 * @cur: the current attribute in the traversal
5421 *
5422 * Traversal function for the "namespace" direction
5423 * the namespace axis contains the namespace nodes of the context node;
5424 * the order of nodes on this axis is implementation-defined; the axis will
5425 * be empty unless the context node is an element
5426 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005427 * We keep the XML namespace node at the end of the list.
5428 *
Owen Taylor3473f882001-02-23 17:55:21 +00005429 * Returns the next element following that axis
5430 */
5431xmlNodePtr
5432xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005433 xmlNodePtr ret;
5434
Owen Taylor3473f882001-02-23 17:55:21 +00005435 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005436 if (cur == (xmlNodePtr) xmlXPathXMLNamespace)
5437 return(NULL);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005438 if ((cur == NULL) || (ctxt->context->tmpNsList == NULL)) {
5439 if (ctxt->context->tmpNsList != NULL)
5440 xmlFree(ctxt->context->tmpNsList);
5441 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005442 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005443 if (ctxt->context->tmpNsList == NULL) return(NULL);
5444 ctxt->context->tmpNsNr = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005445 }
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005446 ret = (xmlNodePtr)ctxt->context->tmpNsList[ctxt->context->tmpNsNr++];
5447 if (ret == NULL) {
5448 xmlFree(ctxt->context->tmpNsList);
5449 ctxt->context->tmpNsList = NULL;
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005450 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005451 }
5452 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005453}
5454
5455/**
5456 * xmlXPathNextAttribute:
5457 * @ctxt: the XPath Parser context
5458 * @cur: the current attribute in the traversal
5459 *
5460 * Traversal function for the "attribute" direction
5461 * TODO: support DTD inherited default attributes
5462 *
5463 * Returns the next element following that axis
5464 */
5465xmlNodePtr
5466xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005467 if (ctxt->context->node == NULL)
5468 return(NULL);
5469 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5470 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005471 if (cur == NULL) {
5472 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5473 return(NULL);
5474 return((xmlNodePtr)ctxt->context->node->properties);
5475 }
5476 return((xmlNodePtr)cur->next);
5477}
5478
5479/************************************************************************
5480 * *
5481 * NodeTest Functions *
5482 * *
5483 ************************************************************************/
5484
Owen Taylor3473f882001-02-23 17:55:21 +00005485#define IS_FUNCTION 200
5486
Owen Taylor3473f882001-02-23 17:55:21 +00005487
5488/************************************************************************
5489 * *
5490 * Implicit tree core function library *
5491 * *
5492 ************************************************************************/
5493
5494/**
5495 * xmlXPathRoot:
5496 * @ctxt: the XPath Parser context
5497 *
5498 * Initialize the context to the root of the document
5499 */
5500void
5501xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5502 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5503 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5504}
5505
5506/************************************************************************
5507 * *
5508 * The explicit core function library *
5509 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5510 * *
5511 ************************************************************************/
5512
5513
5514/**
5515 * xmlXPathLastFunction:
5516 * @ctxt: the XPath Parser context
5517 * @nargs: the number of arguments
5518 *
5519 * Implement the last() XPath function
5520 * number last()
5521 * The last function returns the number of nodes in the context node list.
5522 */
5523void
5524xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5525 CHECK_ARITY(0);
5526 if (ctxt->context->contextSize >= 0) {
5527 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5528#ifdef DEBUG_EXPR
5529 xmlGenericError(xmlGenericErrorContext,
5530 "last() : %d\n", ctxt->context->contextSize);
5531#endif
5532 } else {
5533 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5534 }
5535}
5536
5537/**
5538 * xmlXPathPositionFunction:
5539 * @ctxt: the XPath Parser context
5540 * @nargs: the number of arguments
5541 *
5542 * Implement the position() XPath function
5543 * number position()
5544 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005545 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00005546 * will be equal to last().
5547 */
5548void
5549xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5550 CHECK_ARITY(0);
5551 if (ctxt->context->proximityPosition >= 0) {
5552 valuePush(ctxt,
5553 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5554#ifdef DEBUG_EXPR
5555 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5556 ctxt->context->proximityPosition);
5557#endif
5558 } else {
5559 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5560 }
5561}
5562
5563/**
5564 * xmlXPathCountFunction:
5565 * @ctxt: the XPath Parser context
5566 * @nargs: the number of arguments
5567 *
5568 * Implement the count() XPath function
5569 * number count(node-set)
5570 */
5571void
5572xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5573 xmlXPathObjectPtr cur;
5574
5575 CHECK_ARITY(1);
5576 if ((ctxt->value == NULL) ||
5577 ((ctxt->value->type != XPATH_NODESET) &&
5578 (ctxt->value->type != XPATH_XSLT_TREE)))
5579 XP_ERROR(XPATH_INVALID_TYPE);
5580 cur = valuePop(ctxt);
5581
Daniel Veillard911f49a2001-04-07 15:39:35 +00005582 if ((cur == NULL) || (cur->nodesetval == NULL))
5583 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00005584 else if (cur->type == XPATH_NODESET) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00005585 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00005586 } else {
5587 if ((cur->nodesetval->nodeNr != 1) ||
5588 (cur->nodesetval->nodeTab == NULL)) {
5589 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5590 } else {
5591 xmlNodePtr tmp;
5592 int i = 0;
5593
5594 tmp = cur->nodesetval->nodeTab[0];
5595 if (tmp != NULL) {
5596 tmp = tmp->children;
5597 while (tmp != NULL) {
5598 tmp = tmp->next;
5599 i++;
5600 }
5601 }
5602 valuePush(ctxt, xmlXPathNewFloat((double) i));
5603 }
5604 }
Owen Taylor3473f882001-02-23 17:55:21 +00005605 xmlXPathFreeObject(cur);
5606}
5607
5608/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005609 * xmlXPathGetElementsByIds:
5610 * @doc: the document
5611 * @ids: a whitespace separated list of IDs
5612 *
5613 * Selects elements by their unique ID.
5614 *
5615 * Returns a node-set of selected elements.
5616 */
5617static xmlNodeSetPtr
5618xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5619 xmlNodeSetPtr ret;
5620 const xmlChar *cur = ids;
5621 xmlChar *ID;
5622 xmlAttrPtr attr;
5623 xmlNodePtr elem = NULL;
5624
5625 ret = xmlXPathNodeSetCreate(NULL);
5626
5627 while (IS_BLANK(*cur)) cur++;
5628 while (*cur != 0) {
5629 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
5630 (*cur == '.') || (*cur == '-') ||
5631 (*cur == '_') || (*cur == ':') ||
5632 (IS_COMBINING(*cur)) ||
5633 (IS_EXTENDER(*cur)))
5634 cur++;
5635
5636 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
5637
5638 ID = xmlStrndup(ids, cur - ids);
5639 attr = xmlGetID(doc, ID);
5640 if (attr != NULL) {
5641 elem = attr->parent;
5642 xmlXPathNodeSetAdd(ret, elem);
5643 }
5644 if (ID != NULL)
5645 xmlFree(ID);
5646
5647 while (IS_BLANK(*cur)) cur++;
5648 ids = cur;
5649 }
5650 return(ret);
5651}
5652
5653/**
Owen Taylor3473f882001-02-23 17:55:21 +00005654 * xmlXPathIdFunction:
5655 * @ctxt: the XPath Parser context
5656 * @nargs: the number of arguments
5657 *
5658 * Implement the id() XPath function
5659 * node-set id(object)
5660 * The id function selects elements by their unique ID
5661 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
5662 * then the result is the union of the result of applying id to the
5663 * string value of each of the nodes in the argument node-set. When the
5664 * argument to id is of any other type, the argument is converted to a
5665 * string as if by a call to the string function; the string is split
5666 * into a whitespace-separated list of tokens (whitespace is any sequence
5667 * of characters matching the production S); the result is a node-set
5668 * containing the elements in the same document as the context node that
5669 * have a unique ID equal to any of the tokens in the list.
5670 */
5671void
5672xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005673 xmlChar *tokens;
5674 xmlNodeSetPtr ret;
5675 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00005676
5677 CHECK_ARITY(1);
5678 obj = valuePop(ctxt);
5679 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
5680 if (obj->type == XPATH_NODESET) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005681 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00005682 int i;
5683
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005684 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005685
Daniel Veillard911f49a2001-04-07 15:39:35 +00005686 if (obj->nodesetval != NULL) {
5687 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005688 tokens =
5689 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
5690 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
5691 ret = xmlXPathNodeSetMerge(ret, ns);
5692 xmlXPathFreeNodeSet(ns);
5693 if (tokens != NULL)
5694 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00005695 }
Owen Taylor3473f882001-02-23 17:55:21 +00005696 }
5697
5698 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005699 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005700 return;
5701 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005702 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00005703
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005704 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
5705 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005706
Owen Taylor3473f882001-02-23 17:55:21 +00005707 xmlXPathFreeObject(obj);
5708 return;
5709}
5710
5711/**
5712 * xmlXPathLocalNameFunction:
5713 * @ctxt: the XPath Parser context
5714 * @nargs: the number of arguments
5715 *
5716 * Implement the local-name() XPath function
5717 * string local-name(node-set?)
5718 * The local-name function returns a string containing the local part
5719 * of the name of the node in the argument node-set that is first in
5720 * document order. If the node-set is empty or the first node has no
5721 * name, an empty string is returned. If the argument is omitted it
5722 * defaults to the context node.
5723 */
5724void
5725xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5726 xmlXPathObjectPtr cur;
5727
5728 if (nargs == 0) {
5729 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5730 nargs = 1;
5731 }
5732
5733 CHECK_ARITY(1);
5734 if ((ctxt->value == NULL) ||
5735 ((ctxt->value->type != XPATH_NODESET) &&
5736 (ctxt->value->type != XPATH_XSLT_TREE)))
5737 XP_ERROR(XPATH_INVALID_TYPE);
5738 cur = valuePop(ctxt);
5739
Daniel Veillard911f49a2001-04-07 15:39:35 +00005740 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005741 valuePush(ctxt, xmlXPathNewCString(""));
5742 } else {
5743 int i = 0; /* Should be first in document order !!!!! */
5744 switch (cur->nodesetval->nodeTab[i]->type) {
5745 case XML_ELEMENT_NODE:
5746 case XML_ATTRIBUTE_NODE:
5747 case XML_PI_NODE:
5748 valuePush(ctxt,
5749 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
5750 break;
5751 case XML_NAMESPACE_DECL:
5752 valuePush(ctxt, xmlXPathNewString(
5753 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
5754 break;
5755 default:
5756 valuePush(ctxt, xmlXPathNewCString(""));
5757 }
5758 }
5759 xmlXPathFreeObject(cur);
5760}
5761
5762/**
5763 * xmlXPathNamespaceURIFunction:
5764 * @ctxt: the XPath Parser context
5765 * @nargs: the number of arguments
5766 *
5767 * Implement the namespace-uri() XPath function
5768 * string namespace-uri(node-set?)
5769 * The namespace-uri function returns a string containing the
5770 * namespace URI of the expanded name of the node in the argument
5771 * node-set that is first in document order. If the node-set is empty,
5772 * the first node has no name, or the expanded name has no namespace
5773 * URI, an empty string is returned. If the argument is omitted it
5774 * defaults to the context node.
5775 */
5776void
5777xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5778 xmlXPathObjectPtr cur;
5779
5780 if (nargs == 0) {
5781 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5782 nargs = 1;
5783 }
5784 CHECK_ARITY(1);
5785 if ((ctxt->value == NULL) ||
5786 ((ctxt->value->type != XPATH_NODESET) &&
5787 (ctxt->value->type != XPATH_XSLT_TREE)))
5788 XP_ERROR(XPATH_INVALID_TYPE);
5789 cur = valuePop(ctxt);
5790
Daniel Veillard911f49a2001-04-07 15:39:35 +00005791 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005792 valuePush(ctxt, xmlXPathNewCString(""));
5793 } else {
5794 int i = 0; /* Should be first in document order !!!!! */
5795 switch (cur->nodesetval->nodeTab[i]->type) {
5796 case XML_ELEMENT_NODE:
5797 case XML_ATTRIBUTE_NODE:
5798 if (cur->nodesetval->nodeTab[i]->ns == NULL)
5799 valuePush(ctxt, xmlXPathNewCString(""));
5800 else
5801 valuePush(ctxt, xmlXPathNewString(
5802 cur->nodesetval->nodeTab[i]->ns->href));
5803 break;
5804 default:
5805 valuePush(ctxt, xmlXPathNewCString(""));
5806 }
5807 }
5808 xmlXPathFreeObject(cur);
5809}
5810
5811/**
5812 * xmlXPathNameFunction:
5813 * @ctxt: the XPath Parser context
5814 * @nargs: the number of arguments
5815 *
5816 * Implement the name() XPath function
5817 * string name(node-set?)
5818 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005819 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00005820 * order. The QName must represent the name with respect to the namespace
5821 * declarations in effect on the node whose name is being represented.
5822 * Typically, this will be the form in which the name occurred in the XML
5823 * source. This need not be the case if there are namespace declarations
5824 * in effect on the node that associate multiple prefixes with the same
5825 * namespace. However, an implementation may include information about
5826 * the original prefix in its representation of nodes; in this case, an
5827 * implementation can ensure that the returned string is always the same
5828 * as the QName used in the XML source. If the argument it omitted it
5829 * defaults to the context node.
5830 * Libxml keep the original prefix so the "real qualified name" used is
5831 * returned.
5832 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005833static void
Daniel Veillard04383752001-07-08 14:27:15 +00005834xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
5835{
Owen Taylor3473f882001-02-23 17:55:21 +00005836 xmlXPathObjectPtr cur;
5837
5838 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00005839 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5840 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00005841 }
5842
5843 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00005844 if ((ctxt->value == NULL) ||
5845 ((ctxt->value->type != XPATH_NODESET) &&
5846 (ctxt->value->type != XPATH_XSLT_TREE)))
5847 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00005848 cur = valuePop(ctxt);
5849
Daniel Veillard911f49a2001-04-07 15:39:35 +00005850 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00005851 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00005852 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00005853 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005854
Daniel Veillard04383752001-07-08 14:27:15 +00005855 switch (cur->nodesetval->nodeTab[i]->type) {
5856 case XML_ELEMENT_NODE:
5857 case XML_ATTRIBUTE_NODE:
5858 if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
5859 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL))
5860 valuePush(ctxt,
5861 xmlXPathNewString(cur->nodesetval->
5862 nodeTab[i]->name));
5863
5864 else {
5865 char name[2000];
5866
5867 snprintf(name, sizeof(name), "%s:%s",
5868 (char *) cur->nodesetval->nodeTab[i]->ns->
5869 prefix,
5870 (char *) cur->nodesetval->nodeTab[i]->name);
5871 name[sizeof(name) - 1] = 0;
5872 valuePush(ctxt, xmlXPathNewCString(name));
5873 }
5874 break;
5875 default:
5876 valuePush(ctxt,
5877 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
5878 xmlXPathLocalNameFunction(ctxt, 1);
5879 }
Owen Taylor3473f882001-02-23 17:55:21 +00005880 }
5881 xmlXPathFreeObject(cur);
5882}
5883
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005884
5885/**
Owen Taylor3473f882001-02-23 17:55:21 +00005886 * xmlXPathStringFunction:
5887 * @ctxt: the XPath Parser context
5888 * @nargs: the number of arguments
5889 *
5890 * Implement the string() XPath function
5891 * string string(object?)
5892 * he string function converts an object to a string as follows:
5893 * - A node-set is converted to a string by returning the value of
5894 * the node in the node-set that is first in document order.
5895 * If the node-set is empty, an empty string is returned.
5896 * - A number is converted to a string as follows
5897 * + NaN is converted to the string NaN
5898 * + positive zero is converted to the string 0
5899 * + negative zero is converted to the string 0
5900 * + positive infinity is converted to the string Infinity
5901 * + negative infinity is converted to the string -Infinity
5902 * + if the number is an integer, the number is represented in
5903 * decimal form as a Number with no decimal point and no leading
5904 * zeros, preceded by a minus sign (-) if the number is negative
5905 * + otherwise, the number is represented in decimal form as a
5906 * Number including a decimal point with at least one digit
5907 * before the decimal point and at least one digit after the
5908 * decimal point, preceded by a minus sign (-) if the number
5909 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005910 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00005911 * before the decimal point; beyond the one required digit
5912 * after the decimal point there must be as many, but only as
5913 * many, more digits as are needed to uniquely distinguish the
5914 * number from all other IEEE 754 numeric values.
5915 * - The boolean false value is converted to the string false.
5916 * The boolean true value is converted to the string true.
5917 *
5918 * If the argument is omitted, it defaults to a node-set with the
5919 * context node as its only member.
5920 */
5921void
5922xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5923 xmlXPathObjectPtr cur;
5924
5925 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005926 valuePush(ctxt,
5927 xmlXPathWrapString(
5928 xmlXPathCastNodeToString(ctxt->context->node)));
5929 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005930 }
5931
5932 CHECK_ARITY(1);
5933 cur = valuePop(ctxt);
5934 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005935 cur = xmlXPathConvertString(cur);
5936 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005937}
5938
5939/**
5940 * xmlXPathStringLengthFunction:
5941 * @ctxt: the XPath Parser context
5942 * @nargs: the number of arguments
5943 *
5944 * Implement the string-length() XPath function
5945 * number string-length(string?)
5946 * The string-length returns the number of characters in the string
5947 * (see [3.6 Strings]). If the argument is omitted, it defaults to
5948 * the context node converted to a string, in other words the value
5949 * of the context node.
5950 */
5951void
5952xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5953 xmlXPathObjectPtr cur;
5954
5955 if (nargs == 0) {
5956 if (ctxt->context->node == NULL) {
5957 valuePush(ctxt, xmlXPathNewFloat(0));
5958 } else {
5959 xmlChar *content;
5960
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005961 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00005962 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00005963 xmlFree(content);
5964 }
5965 return;
5966 }
5967 CHECK_ARITY(1);
5968 CAST_TO_STRING;
5969 CHECK_TYPE(XPATH_STRING);
5970 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00005971 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00005972 xmlXPathFreeObject(cur);
5973}
5974
5975/**
5976 * xmlXPathConcatFunction:
5977 * @ctxt: the XPath Parser context
5978 * @nargs: the number of arguments
5979 *
5980 * Implement the concat() XPath function
5981 * string concat(string, string, string*)
5982 * The concat function returns the concatenation of its arguments.
5983 */
5984void
5985xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5986 xmlXPathObjectPtr cur, newobj;
5987 xmlChar *tmp;
5988
5989 if (nargs < 2) {
5990 CHECK_ARITY(2);
5991 }
5992
5993 CAST_TO_STRING;
5994 cur = valuePop(ctxt);
5995 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
5996 xmlXPathFreeObject(cur);
5997 return;
5998 }
5999 nargs--;
6000
6001 while (nargs > 0) {
6002 CAST_TO_STRING;
6003 newobj = valuePop(ctxt);
6004 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6005 xmlXPathFreeObject(newobj);
6006 xmlXPathFreeObject(cur);
6007 XP_ERROR(XPATH_INVALID_TYPE);
6008 }
6009 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6010 newobj->stringval = cur->stringval;
6011 cur->stringval = tmp;
6012
6013 xmlXPathFreeObject(newobj);
6014 nargs--;
6015 }
6016 valuePush(ctxt, cur);
6017}
6018
6019/**
6020 * xmlXPathContainsFunction:
6021 * @ctxt: the XPath Parser context
6022 * @nargs: the number of arguments
6023 *
6024 * Implement the contains() XPath function
6025 * boolean contains(string, string)
6026 * The contains function returns true if the first argument string
6027 * contains the second argument string, and otherwise returns false.
6028 */
6029void
6030xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6031 xmlXPathObjectPtr hay, needle;
6032
6033 CHECK_ARITY(2);
6034 CAST_TO_STRING;
6035 CHECK_TYPE(XPATH_STRING);
6036 needle = valuePop(ctxt);
6037 CAST_TO_STRING;
6038 hay = valuePop(ctxt);
6039 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6040 xmlXPathFreeObject(hay);
6041 xmlXPathFreeObject(needle);
6042 XP_ERROR(XPATH_INVALID_TYPE);
6043 }
6044 if (xmlStrstr(hay->stringval, needle->stringval))
6045 valuePush(ctxt, xmlXPathNewBoolean(1));
6046 else
6047 valuePush(ctxt, xmlXPathNewBoolean(0));
6048 xmlXPathFreeObject(hay);
6049 xmlXPathFreeObject(needle);
6050}
6051
6052/**
6053 * xmlXPathStartsWithFunction:
6054 * @ctxt: the XPath Parser context
6055 * @nargs: the number of arguments
6056 *
6057 * Implement the starts-with() XPath function
6058 * boolean starts-with(string, string)
6059 * The starts-with function returns true if the first argument string
6060 * starts with the second argument string, and otherwise returns false.
6061 */
6062void
6063xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6064 xmlXPathObjectPtr hay, needle;
6065 int n;
6066
6067 CHECK_ARITY(2);
6068 CAST_TO_STRING;
6069 CHECK_TYPE(XPATH_STRING);
6070 needle = valuePop(ctxt);
6071 CAST_TO_STRING;
6072 hay = valuePop(ctxt);
6073 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6074 xmlXPathFreeObject(hay);
6075 xmlXPathFreeObject(needle);
6076 XP_ERROR(XPATH_INVALID_TYPE);
6077 }
6078 n = xmlStrlen(needle->stringval);
6079 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6080 valuePush(ctxt, xmlXPathNewBoolean(0));
6081 else
6082 valuePush(ctxt, xmlXPathNewBoolean(1));
6083 xmlXPathFreeObject(hay);
6084 xmlXPathFreeObject(needle);
6085}
6086
6087/**
6088 * xmlXPathSubstringFunction:
6089 * @ctxt: the XPath Parser context
6090 * @nargs: the number of arguments
6091 *
6092 * Implement the substring() XPath function
6093 * string substring(string, number, number?)
6094 * The substring function returns the substring of the first argument
6095 * starting at the position specified in the second argument with
6096 * length specified in the third argument. For example,
6097 * substring("12345",2,3) returns "234". If the third argument is not
6098 * specified, it returns the substring starting at the position specified
6099 * in the second argument and continuing to the end of the string. For
6100 * example, substring("12345",2) returns "2345". More precisely, each
6101 * character in the string (see [3.6 Strings]) is considered to have a
6102 * numeric position: the position of the first character is 1, the position
6103 * of the second character is 2 and so on. The returned substring contains
6104 * those characters for which the position of the character is greater than
6105 * or equal to the second argument and, if the third argument is specified,
6106 * less than the sum of the second and third arguments; the comparisons
6107 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6108 * - substring("12345", 1.5, 2.6) returns "234"
6109 * - substring("12345", 0, 3) returns "12"
6110 * - substring("12345", 0 div 0, 3) returns ""
6111 * - substring("12345", 1, 0 div 0) returns ""
6112 * - substring("12345", -42, 1 div 0) returns "12345"
6113 * - substring("12345", -1 div 0, 1 div 0) returns ""
6114 */
6115void
6116xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6117 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006118 double le=0, in;
6119 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006120 xmlChar *ret;
6121
Owen Taylor3473f882001-02-23 17:55:21 +00006122 if (nargs < 2) {
6123 CHECK_ARITY(2);
6124 }
6125 if (nargs > 3) {
6126 CHECK_ARITY(3);
6127 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006128 /*
6129 * take care of possible last (position) argument
6130 */
Owen Taylor3473f882001-02-23 17:55:21 +00006131 if (nargs == 3) {
6132 CAST_TO_NUMBER;
6133 CHECK_TYPE(XPATH_NUMBER);
6134 len = valuePop(ctxt);
6135 le = len->floatval;
6136 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006137 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006138
Owen Taylor3473f882001-02-23 17:55:21 +00006139 CAST_TO_NUMBER;
6140 CHECK_TYPE(XPATH_NUMBER);
6141 start = valuePop(ctxt);
6142 in = start->floatval;
6143 xmlXPathFreeObject(start);
6144 CAST_TO_STRING;
6145 CHECK_TYPE(XPATH_STRING);
6146 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006147 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006148
Daniel Veillard97ac1312001-05-30 19:14:17 +00006149 /*
6150 * If last pos not present, calculate last position
6151 */
6152 if (nargs != 3)
6153 le = m;
6154
6155 /*
6156 * To meet our requirements, initial index calculations
6157 * must be done before we convert to integer format
6158 *
6159 * First we normalize indices
6160 */
6161 in -= 1.0;
6162 le += in;
6163 if (in < 0.0)
6164 in = 0.0;
6165 if (le > (double)m)
6166 le = (double)m;
6167
6168 /*
6169 * Now we go to integer form, rounding up
6170 */
Owen Taylor3473f882001-02-23 17:55:21 +00006171 i = (int) in;
6172 if (((double)i) != in) i++;
6173
Owen Taylor3473f882001-02-23 17:55:21 +00006174 l = (int) le;
6175 if (((double)l) != le) l++;
6176
Daniel Veillard97ac1312001-05-30 19:14:17 +00006177 if (l > m) l=m;
Owen Taylor3473f882001-02-23 17:55:21 +00006178
6179 /* number of chars to copy */
6180 l -= i;
6181
Daniel Veillard97ac1312001-05-30 19:14:17 +00006182 ret = xmlUTF8Strsub(str->stringval, i, l);
Owen Taylor3473f882001-02-23 17:55:21 +00006183 if (ret == NULL)
6184 valuePush(ctxt, xmlXPathNewCString(""));
6185 else {
6186 valuePush(ctxt, xmlXPathNewString(ret));
6187 xmlFree(ret);
6188 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006189
Owen Taylor3473f882001-02-23 17:55:21 +00006190 xmlXPathFreeObject(str);
6191}
6192
6193/**
6194 * xmlXPathSubstringBeforeFunction:
6195 * @ctxt: the XPath Parser context
6196 * @nargs: the number of arguments
6197 *
6198 * Implement the substring-before() XPath function
6199 * string substring-before(string, string)
6200 * The substring-before function returns the substring of the first
6201 * argument string that precedes the first occurrence of the second
6202 * argument string in the first argument string, or the empty string
6203 * if the first argument string does not contain the second argument
6204 * string. For example, substring-before("1999/04/01","/") returns 1999.
6205 */
6206void
6207xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6208 xmlXPathObjectPtr str;
6209 xmlXPathObjectPtr find;
6210 xmlBufferPtr target;
6211 const xmlChar *point;
6212 int offset;
6213
6214 CHECK_ARITY(2);
6215 CAST_TO_STRING;
6216 find = valuePop(ctxt);
6217 CAST_TO_STRING;
6218 str = valuePop(ctxt);
6219
6220 target = xmlBufferCreate();
6221 if (target) {
6222 point = xmlStrstr(str->stringval, find->stringval);
6223 if (point) {
6224 offset = (int)(point - str->stringval);
6225 xmlBufferAdd(target, str->stringval, offset);
6226 }
6227 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6228 xmlBufferFree(target);
6229 }
6230
6231 xmlXPathFreeObject(str);
6232 xmlXPathFreeObject(find);
6233}
6234
6235/**
6236 * xmlXPathSubstringAfterFunction:
6237 * @ctxt: the XPath Parser context
6238 * @nargs: the number of arguments
6239 *
6240 * Implement the substring-after() XPath function
6241 * string substring-after(string, string)
6242 * The substring-after function returns the substring of the first
6243 * argument string that follows the first occurrence of the second
6244 * argument string in the first argument string, or the empty stringi
6245 * if the first argument string does not contain the second argument
6246 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6247 * and substring-after("1999/04/01","19") returns 99/04/01.
6248 */
6249void
6250xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6251 xmlXPathObjectPtr str;
6252 xmlXPathObjectPtr find;
6253 xmlBufferPtr target;
6254 const xmlChar *point;
6255 int offset;
6256
6257 CHECK_ARITY(2);
6258 CAST_TO_STRING;
6259 find = valuePop(ctxt);
6260 CAST_TO_STRING;
6261 str = valuePop(ctxt);
6262
6263 target = xmlBufferCreate();
6264 if (target) {
6265 point = xmlStrstr(str->stringval, find->stringval);
6266 if (point) {
6267 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6268 xmlBufferAdd(target, &str->stringval[offset],
6269 xmlStrlen(str->stringval) - offset);
6270 }
6271 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6272 xmlBufferFree(target);
6273 }
6274
6275 xmlXPathFreeObject(str);
6276 xmlXPathFreeObject(find);
6277}
6278
6279/**
6280 * xmlXPathNormalizeFunction:
6281 * @ctxt: the XPath Parser context
6282 * @nargs: the number of arguments
6283 *
6284 * Implement the normalize-space() XPath function
6285 * string normalize-space(string?)
6286 * The normalize-space function returns the argument string with white
6287 * space normalized by stripping leading and trailing whitespace
6288 * and replacing sequences of whitespace characters by a single
6289 * space. Whitespace characters are the same allowed by the S production
6290 * in XML. If the argument is omitted, it defaults to the context
6291 * node converted to a string, in other words the value of the context node.
6292 */
6293void
6294xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6295 xmlXPathObjectPtr obj = NULL;
6296 xmlChar *source = NULL;
6297 xmlBufferPtr target;
6298 xmlChar blank;
6299
6300 if (nargs == 0) {
6301 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006302 valuePush(ctxt,
6303 xmlXPathWrapString(
6304 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006305 nargs = 1;
6306 }
6307
6308 CHECK_ARITY(1);
6309 CAST_TO_STRING;
6310 CHECK_TYPE(XPATH_STRING);
6311 obj = valuePop(ctxt);
6312 source = obj->stringval;
6313
6314 target = xmlBufferCreate();
6315 if (target && source) {
6316
6317 /* Skip leading whitespaces */
6318 while (IS_BLANK(*source))
6319 source++;
6320
6321 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6322 blank = 0;
6323 while (*source) {
6324 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006325 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006326 } else {
6327 if (blank) {
6328 xmlBufferAdd(target, &blank, 1);
6329 blank = 0;
6330 }
6331 xmlBufferAdd(target, source, 1);
6332 }
6333 source++;
6334 }
6335
6336 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6337 xmlBufferFree(target);
6338 }
6339 xmlXPathFreeObject(obj);
6340}
6341
6342/**
6343 * xmlXPathTranslateFunction:
6344 * @ctxt: the XPath Parser context
6345 * @nargs: the number of arguments
6346 *
6347 * Implement the translate() XPath function
6348 * string translate(string, string, string)
6349 * The translate function returns the first argument string with
6350 * occurrences of characters in the second argument string replaced
6351 * by the character at the corresponding position in the third argument
6352 * string. For example, translate("bar","abc","ABC") returns the string
6353 * BAr. If there is a character in the second argument string with no
6354 * character at a corresponding position in the third argument string
6355 * (because the second argument string is longer than the third argument
6356 * string), then occurrences of that character in the first argument
6357 * string are removed. For example, translate("--aaa--","abc-","ABC")
6358 * returns "AAA". If a character occurs more than once in second
6359 * argument string, then the first occurrence determines the replacement
6360 * character. If the third argument string is longer than the second
6361 * argument string, then excess characters are ignored.
6362 */
6363void
6364xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006365 xmlXPathObjectPtr str;
6366 xmlXPathObjectPtr from;
6367 xmlXPathObjectPtr to;
6368 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006369 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006370 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006371 xmlChar *point;
6372 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006373
Daniel Veillarde043ee12001-04-16 14:08:07 +00006374 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006375
Daniel Veillarde043ee12001-04-16 14:08:07 +00006376 CAST_TO_STRING;
6377 to = valuePop(ctxt);
6378 CAST_TO_STRING;
6379 from = valuePop(ctxt);
6380 CAST_TO_STRING;
6381 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006382
Daniel Veillarde043ee12001-04-16 14:08:07 +00006383 target = xmlBufferCreate();
6384 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006385 max = xmlUTF8Strlen(to->stringval);
6386 for (cptr = str->stringval; (ch=*cptr); ) {
6387 offset = xmlUTF8Strloc(from->stringval, cptr);
6388 if (offset >= 0) {
6389 if (offset < max) {
6390 point = xmlUTF8Strpos(to->stringval, offset);
6391 if (point)
6392 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6393 }
6394 } else
6395 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6396
6397 /* Step to next character in input */
6398 cptr++;
6399 if ( ch & 0x80 ) {
6400 /* if not simple ascii, verify proper format */
6401 if ( (ch & 0xc0) != 0xc0 ) {
6402 xmlGenericError(xmlGenericErrorContext,
6403 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6404 break;
6405 }
6406 /* then skip over remaining bytes for this char */
6407 while ( (ch <<= 1) & 0x80 )
6408 if ( (*cptr++ & 0xc0) != 0x80 ) {
6409 xmlGenericError(xmlGenericErrorContext,
6410 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6411 break;
6412 }
6413 if (ch & 0x80) /* must have had error encountered */
6414 break;
6415 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006416 }
Owen Taylor3473f882001-02-23 17:55:21 +00006417 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006418 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6419 xmlBufferFree(target);
6420 xmlXPathFreeObject(str);
6421 xmlXPathFreeObject(from);
6422 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006423}
6424
6425/**
6426 * xmlXPathBooleanFunction:
6427 * @ctxt: the XPath Parser context
6428 * @nargs: the number of arguments
6429 *
6430 * Implement the boolean() XPath function
6431 * boolean boolean(object)
6432 * he boolean function converts its argument to a boolean as follows:
6433 * - a number is true if and only if it is neither positive or
6434 * negative zero nor NaN
6435 * - a node-set is true if and only if it is non-empty
6436 * - a string is true if and only if its length is non-zero
6437 */
6438void
6439xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6440 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006441
6442 CHECK_ARITY(1);
6443 cur = valuePop(ctxt);
6444 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006445 cur = xmlXPathConvertBoolean(cur);
6446 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006447}
6448
6449/**
6450 * xmlXPathNotFunction:
6451 * @ctxt: the XPath Parser context
6452 * @nargs: the number of arguments
6453 *
6454 * Implement the not() XPath function
6455 * boolean not(boolean)
6456 * The not function returns true if its argument is false,
6457 * and false otherwise.
6458 */
6459void
6460xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6461 CHECK_ARITY(1);
6462 CAST_TO_BOOLEAN;
6463 CHECK_TYPE(XPATH_BOOLEAN);
6464 ctxt->value->boolval = ! ctxt->value->boolval;
6465}
6466
6467/**
6468 * xmlXPathTrueFunction:
6469 * @ctxt: the XPath Parser context
6470 * @nargs: the number of arguments
6471 *
6472 * Implement the true() XPath function
6473 * boolean true()
6474 */
6475void
6476xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6477 CHECK_ARITY(0);
6478 valuePush(ctxt, xmlXPathNewBoolean(1));
6479}
6480
6481/**
6482 * xmlXPathFalseFunction:
6483 * @ctxt: the XPath Parser context
6484 * @nargs: the number of arguments
6485 *
6486 * Implement the false() XPath function
6487 * boolean false()
6488 */
6489void
6490xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6491 CHECK_ARITY(0);
6492 valuePush(ctxt, xmlXPathNewBoolean(0));
6493}
6494
6495/**
6496 * xmlXPathLangFunction:
6497 * @ctxt: the XPath Parser context
6498 * @nargs: the number of arguments
6499 *
6500 * Implement the lang() XPath function
6501 * boolean lang(string)
6502 * The lang function returns true or false depending on whether the
6503 * language of the context node as specified by xml:lang attributes
6504 * is the same as or is a sublanguage of the language specified by
6505 * the argument string. The language of the context node is determined
6506 * by the value of the xml:lang attribute on the context node, or, if
6507 * the context node has no xml:lang attribute, by the value of the
6508 * xml:lang attribute on the nearest ancestor of the context node that
6509 * has an xml:lang attribute. If there is no such attribute, then lang
6510 * returns false. If there is such an attribute, then lang returns
6511 * true if the attribute value is equal to the argument ignoring case,
6512 * or if there is some suffix starting with - such that the attribute
6513 * value is equal to the argument ignoring that suffix of the attribute
6514 * value and ignoring case.
6515 */
6516void
6517xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6518 xmlXPathObjectPtr val;
6519 const xmlChar *theLang;
6520 const xmlChar *lang;
6521 int ret = 0;
6522 int i;
6523
6524 CHECK_ARITY(1);
6525 CAST_TO_STRING;
6526 CHECK_TYPE(XPATH_STRING);
6527 val = valuePop(ctxt);
6528 lang = val->stringval;
6529 theLang = xmlNodeGetLang(ctxt->context->node);
6530 if ((theLang != NULL) && (lang != NULL)) {
6531 for (i = 0;lang[i] != 0;i++)
6532 if (toupper(lang[i]) != toupper(theLang[i]))
6533 goto not_equal;
6534 ret = 1;
6535 }
6536not_equal:
6537 xmlXPathFreeObject(val);
6538 valuePush(ctxt, xmlXPathNewBoolean(ret));
6539}
6540
6541/**
6542 * xmlXPathNumberFunction:
6543 * @ctxt: the XPath Parser context
6544 * @nargs: the number of arguments
6545 *
6546 * Implement the number() XPath function
6547 * number number(object?)
6548 */
6549void
6550xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6551 xmlXPathObjectPtr cur;
6552 double res;
6553
6554 if (nargs == 0) {
6555 if (ctxt->context->node == NULL) {
6556 valuePush(ctxt, xmlXPathNewFloat(0.0));
6557 } else {
6558 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6559
6560 res = xmlXPathStringEvalNumber(content);
6561 valuePush(ctxt, xmlXPathNewFloat(res));
6562 xmlFree(content);
6563 }
6564 return;
6565 }
6566
6567 CHECK_ARITY(1);
6568 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006569 cur = xmlXPathConvertNumber(cur);
6570 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006571}
6572
6573/**
6574 * xmlXPathSumFunction:
6575 * @ctxt: the XPath Parser context
6576 * @nargs: the number of arguments
6577 *
6578 * Implement the sum() XPath function
6579 * number sum(node-set)
6580 * The sum function returns the sum of the values of the nodes in
6581 * the argument node-set.
6582 */
6583void
6584xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6585 xmlXPathObjectPtr cur;
6586 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006587 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00006588
6589 CHECK_ARITY(1);
6590 if ((ctxt->value == NULL) ||
6591 ((ctxt->value->type != XPATH_NODESET) &&
6592 (ctxt->value->type != XPATH_XSLT_TREE)))
6593 XP_ERROR(XPATH_INVALID_TYPE);
6594 cur = valuePop(ctxt);
6595
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006596 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006597 valuePush(ctxt, xmlXPathNewFloat(0.0));
6598 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006599 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
6600 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006601 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006602 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00006603 }
6604 xmlXPathFreeObject(cur);
6605}
6606
6607/**
6608 * xmlXPathFloorFunction:
6609 * @ctxt: the XPath Parser context
6610 * @nargs: the number of arguments
6611 *
6612 * Implement the floor() XPath function
6613 * number floor(number)
6614 * The floor function returns the largest (closest to positive infinity)
6615 * number that is not greater than the argument and that is an integer.
6616 */
6617void
6618xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006619 double f;
6620
Owen Taylor3473f882001-02-23 17:55:21 +00006621 CHECK_ARITY(1);
6622 CAST_TO_NUMBER;
6623 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006624
6625 f = (double)((int) ctxt->value->floatval);
6626 if (f != ctxt->value->floatval) {
6627 if (ctxt->value->floatval > 0)
6628 ctxt->value->floatval = f;
6629 else
6630 ctxt->value->floatval = f - 1;
6631 }
Owen Taylor3473f882001-02-23 17:55:21 +00006632}
6633
6634/**
6635 * xmlXPathCeilingFunction:
6636 * @ctxt: the XPath Parser context
6637 * @nargs: the number of arguments
6638 *
6639 * Implement the ceiling() XPath function
6640 * number ceiling(number)
6641 * The ceiling function returns the smallest (closest to negative infinity)
6642 * number that is not less than the argument and that is an integer.
6643 */
6644void
6645xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6646 double f;
6647
6648 CHECK_ARITY(1);
6649 CAST_TO_NUMBER;
6650 CHECK_TYPE(XPATH_NUMBER);
6651
6652#if 0
6653 ctxt->value->floatval = ceil(ctxt->value->floatval);
6654#else
6655 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006656 if (f != ctxt->value->floatval) {
6657 if (ctxt->value->floatval > 0)
6658 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00006659 else {
6660 if (ctxt->value->floatval < 0 && f == 0)
6661 ctxt->value->floatval = xmlXPathNZERO;
6662 else
6663 ctxt->value->floatval = f;
6664 }
6665
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006666 }
Owen Taylor3473f882001-02-23 17:55:21 +00006667#endif
6668}
6669
6670/**
6671 * xmlXPathRoundFunction:
6672 * @ctxt: the XPath Parser context
6673 * @nargs: the number of arguments
6674 *
6675 * Implement the round() XPath function
6676 * number round(number)
6677 * The round function returns the number that is closest to the
6678 * argument and that is an integer. If there are two such numbers,
6679 * then the one that is even is returned.
6680 */
6681void
6682xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6683 double f;
6684
6685 CHECK_ARITY(1);
6686 CAST_TO_NUMBER;
6687 CHECK_TYPE(XPATH_NUMBER);
6688
Daniel Veillardcda96922001-08-21 10:56:31 +00006689 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
6690 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
6691 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00006692 (ctxt->value->floatval == 0.0))
6693 return;
6694
Owen Taylor3473f882001-02-23 17:55:21 +00006695 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006696 if (ctxt->value->floatval < 0) {
6697 if (ctxt->value->floatval < f - 0.5)
6698 ctxt->value->floatval = f - 1;
6699 else
6700 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00006701 if (ctxt->value->floatval == 0)
6702 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006703 } else {
6704 if (ctxt->value->floatval < f + 0.5)
6705 ctxt->value->floatval = f;
6706 else
6707 ctxt->value->floatval = f + 1;
6708 }
Owen Taylor3473f882001-02-23 17:55:21 +00006709}
6710
6711/************************************************************************
6712 * *
6713 * The Parser *
6714 * *
6715 ************************************************************************/
6716
6717/*
6718 * a couple of forward declarations since we use a recursive call based
6719 * implementation.
6720 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006721static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006722static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006723static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006724#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006725static void xmlXPathCompRelLocationPath(xmlXPathParserContextPtr ctxt);
6726#define xmlXPathCompRelativeLocationPath xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00006727#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006728static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006729#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00006730static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
6731 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00006732
6733/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00006734 * xmlXPathCurrentChar:
6735 * @ctxt: the XPath parser context
6736 * @cur: pointer to the beginning of the char
6737 * @len: pointer to the length of the char read
6738 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006739 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00006740 * bytes in the input buffer.
6741 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006742 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00006743 */
6744
6745static int
6746xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
6747 unsigned char c;
6748 unsigned int val;
6749 const xmlChar *cur;
6750
6751 if (ctxt == NULL)
6752 return(0);
6753 cur = ctxt->cur;
6754
6755 /*
6756 * We are supposed to handle UTF8, check it's valid
6757 * From rfc2044: encoding of the Unicode values on UTF-8:
6758 *
6759 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
6760 * 0000 0000-0000 007F 0xxxxxxx
6761 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
6762 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
6763 *
6764 * Check for the 0x110000 limit too
6765 */
6766 c = *cur;
6767 if (c & 0x80) {
6768 if ((cur[1] & 0xc0) != 0x80)
6769 goto encoding_error;
6770 if ((c & 0xe0) == 0xe0) {
6771
6772 if ((cur[2] & 0xc0) != 0x80)
6773 goto encoding_error;
6774 if ((c & 0xf0) == 0xf0) {
6775 if (((c & 0xf8) != 0xf0) ||
6776 ((cur[3] & 0xc0) != 0x80))
6777 goto encoding_error;
6778 /* 4-byte code */
6779 *len = 4;
6780 val = (cur[0] & 0x7) << 18;
6781 val |= (cur[1] & 0x3f) << 12;
6782 val |= (cur[2] & 0x3f) << 6;
6783 val |= cur[3] & 0x3f;
6784 } else {
6785 /* 3-byte code */
6786 *len = 3;
6787 val = (cur[0] & 0xf) << 12;
6788 val |= (cur[1] & 0x3f) << 6;
6789 val |= cur[2] & 0x3f;
6790 }
6791 } else {
6792 /* 2-byte code */
6793 *len = 2;
6794 val = (cur[0] & 0x1f) << 6;
6795 val |= cur[1] & 0x3f;
6796 }
6797 if (!IS_CHAR(val)) {
6798 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
6799 }
6800 return(val);
6801 } else {
6802 /* 1-byte code */
6803 *len = 1;
6804 return((int) *cur);
6805 }
6806encoding_error:
6807 /*
6808 * If we detect an UTF8 error that probably mean that the
6809 * input encoding didn't get properly advertized in the
6810 * declaration header. Report the error and switch the encoding
6811 * to ISO-Latin-1 (if you don't like this policy, just declare the
6812 * encoding !)
6813 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00006814 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00006815 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00006816}
6817
6818/**
Owen Taylor3473f882001-02-23 17:55:21 +00006819 * xmlXPathParseNCName:
6820 * @ctxt: the XPath Parser context
6821 *
6822 * parse an XML namespace non qualified name.
6823 *
6824 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
6825 *
6826 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
6827 * CombiningChar | Extender
6828 *
6829 * Returns the namespace name or NULL
6830 */
6831
6832xmlChar *
6833xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00006834 const xmlChar *in;
6835 xmlChar *ret;
6836 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006837
Daniel Veillard2156a562001-04-28 12:24:34 +00006838 /*
6839 * Accelerator for simple ASCII names
6840 */
6841 in = ctxt->cur;
6842 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6843 ((*in >= 0x41) && (*in <= 0x5A)) ||
6844 (*in == '_')) {
6845 in++;
6846 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6847 ((*in >= 0x41) && (*in <= 0x5A)) ||
6848 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00006849 (*in == '_') || (*in == '.') ||
6850 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00006851 in++;
6852 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
6853 (*in == '[') || (*in == ']') || (*in == ':') ||
6854 (*in == '@') || (*in == '*')) {
6855 count = in - ctxt->cur;
6856 if (count == 0)
6857 return(NULL);
6858 ret = xmlStrndup(ctxt->cur, count);
6859 ctxt->cur = in;
6860 return(ret);
6861 }
6862 }
6863 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00006864}
6865
Daniel Veillard2156a562001-04-28 12:24:34 +00006866
Owen Taylor3473f882001-02-23 17:55:21 +00006867/**
6868 * xmlXPathParseQName:
6869 * @ctxt: the XPath Parser context
6870 * @prefix: a xmlChar **
6871 *
6872 * parse an XML qualified name
6873 *
6874 * [NS 5] QName ::= (Prefix ':')? LocalPart
6875 *
6876 * [NS 6] Prefix ::= NCName
6877 *
6878 * [NS 7] LocalPart ::= NCName
6879 *
6880 * Returns the function returns the local part, and prefix is updated
6881 * to get the Prefix if any.
6882 */
6883
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006884static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006885xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
6886 xmlChar *ret = NULL;
6887
6888 *prefix = NULL;
6889 ret = xmlXPathParseNCName(ctxt);
6890 if (CUR == ':') {
6891 *prefix = ret;
6892 NEXT;
6893 ret = xmlXPathParseNCName(ctxt);
6894 }
6895 return(ret);
6896}
6897
6898/**
6899 * xmlXPathParseName:
6900 * @ctxt: the XPath Parser context
6901 *
6902 * parse an XML name
6903 *
6904 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
6905 * CombiningChar | Extender
6906 *
6907 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
6908 *
6909 * Returns the namespace name or NULL
6910 */
6911
6912xmlChar *
6913xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006914 const xmlChar *in;
6915 xmlChar *ret;
6916 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006917
Daniel Veillard61d80a22001-04-27 17:13:01 +00006918 /*
6919 * Accelerator for simple ASCII names
6920 */
6921 in = ctxt->cur;
6922 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6923 ((*in >= 0x41) && (*in <= 0x5A)) ||
6924 (*in == '_') || (*in == ':')) {
6925 in++;
6926 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6927 ((*in >= 0x41) && (*in <= 0x5A)) ||
6928 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00006929 (*in == '_') || (*in == '-') ||
6930 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00006931 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00006932 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006933 count = in - ctxt->cur;
6934 ret = xmlStrndup(ctxt->cur, count);
6935 ctxt->cur = in;
6936 return(ret);
6937 }
6938 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006939 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00006940}
6941
Daniel Veillard61d80a22001-04-27 17:13:01 +00006942static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00006943xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006944 xmlChar buf[XML_MAX_NAMELEN + 5];
6945 int len = 0, l;
6946 int c;
6947
6948 /*
6949 * Handler for more complex cases
6950 */
6951 c = CUR_CHAR(l);
6952 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00006953 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
6954 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00006955 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00006956 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006957 return(NULL);
6958 }
6959
6960 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
6961 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
6962 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00006963 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00006964 (IS_COMBINING(c)) ||
6965 (IS_EXTENDER(c)))) {
6966 COPY_BUF(l,buf,len,c);
6967 NEXTL(l);
6968 c = CUR_CHAR(l);
6969 if (len >= XML_MAX_NAMELEN) {
6970 /*
6971 * Okay someone managed to make a huge name, so he's ready to pay
6972 * for the processing speed.
6973 */
6974 xmlChar *buffer;
6975 int max = len * 2;
6976
6977 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
6978 if (buffer == NULL) {
6979 XP_ERROR0(XPATH_MEMORY_ERROR);
6980 }
6981 memcpy(buffer, buf, len);
6982 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
6983 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00006984 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00006985 (IS_COMBINING(c)) ||
6986 (IS_EXTENDER(c))) {
6987 if (len + 10 > max) {
6988 max *= 2;
6989 buffer = (xmlChar *) xmlRealloc(buffer,
6990 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00006991 if (buffer == NULL) {
6992 XP_ERROR0(XPATH_MEMORY_ERROR);
6993 }
6994 }
6995 COPY_BUF(l,buffer,len,c);
6996 NEXTL(l);
6997 c = CUR_CHAR(l);
6998 }
6999 buffer[len] = 0;
7000 return(buffer);
7001 }
7002 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007003 if (len == 0)
7004 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007005 return(xmlStrndup(buf, len));
7006}
Owen Taylor3473f882001-02-23 17:55:21 +00007007/**
7008 * xmlXPathStringEvalNumber:
7009 * @str: A string to scan
7010 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00007011 * [30a] Float ::= Number ('e' Digits?)?
7012 *
Owen Taylor3473f882001-02-23 17:55:21 +00007013 * [30] Number ::= Digits ('.' Digits?)?
7014 * | '.' Digits
7015 * [31] Digits ::= [0-9]+
7016 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007017 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00007018 * In complement of the Number expression, this function also handles
7019 * negative values : '-' Number.
7020 *
7021 * Returns the double value.
7022 */
7023double
7024xmlXPathStringEvalNumber(const xmlChar *str) {
7025 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00007026 double ret;
Owen Taylor3473f882001-02-23 17:55:21 +00007027 double mult = 1;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007028 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007029 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007030 int exponent = 0;
7031 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007032#ifdef __GNUC__
7033 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007034 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007035#endif
Bjorn Reese70a9da52001-04-21 16:57:29 +00007036
Owen Taylor3473f882001-02-23 17:55:21 +00007037 while (IS_BLANK(*cur)) cur++;
7038 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7039 return(xmlXPathNAN);
7040 }
7041 if (*cur == '-') {
7042 isneg = 1;
7043 cur++;
7044 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007045
7046#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007047 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007048 * tmp/temp is a workaround against a gcc compiler bug
7049 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007050 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007051 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007052 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007053 ret = ret * 10;
7054 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00007055 ok = 1;
7056 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00007057 temp = (double) tmp;
7058 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007059 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007060#else
Daniel Veillard7b416132002-03-07 08:36:03 +00007061 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007062 while ((*cur >= '0') && (*cur <= '9')) {
7063 ret = ret * 10 + (*cur - '0');
7064 ok = 1;
7065 cur++;
7066 }
7067#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007068
Owen Taylor3473f882001-02-23 17:55:21 +00007069 if (*cur == '.') {
7070 cur++;
7071 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7072 return(xmlXPathNAN);
7073 }
7074 while ((*cur >= '0') && (*cur <= '9')) {
7075 mult /= 10;
7076 ret = ret + (*cur - '0') * mult;
7077 cur++;
7078 }
7079 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007080 if ((*cur == 'e') || (*cur == 'E')) {
7081 cur++;
7082 if (*cur == '-') {
7083 is_exponent_negative = 1;
7084 cur++;
7085 }
7086 while ((*cur >= '0') && (*cur <= '9')) {
7087 exponent = exponent * 10 + (*cur - '0');
7088 cur++;
7089 }
7090 }
Owen Taylor3473f882001-02-23 17:55:21 +00007091 while (IS_BLANK(*cur)) cur++;
7092 if (*cur != 0) return(xmlXPathNAN);
7093 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007094 if (is_exponent_negative) exponent = -exponent;
7095 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007096 return(ret);
7097}
7098
7099/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007100 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007101 * @ctxt: the XPath Parser context
7102 *
7103 * [30] Number ::= Digits ('.' Digits?)?
7104 * | '.' Digits
7105 * [31] Digits ::= [0-9]+
7106 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007107 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007108 *
7109 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007110static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007111xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7112{
Owen Taylor3473f882001-02-23 17:55:21 +00007113 double ret = 0.0;
7114 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007115 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007116 int exponent = 0;
7117 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007118#ifdef __GNUC__
7119 unsigned long tmp = 0;
7120 double temp;
7121#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007122
7123 CHECK_ERROR;
7124 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7125 XP_ERROR(XPATH_NUMBER_ERROR);
7126 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007127#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007128 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007129 * tmp/temp is a workaround against a gcc compiler bug
7130 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007131 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007132 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007133 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007134 ret = ret * 10;
7135 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007136 ok = 1;
7137 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007138 temp = (double) tmp;
7139 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007140 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007141#else
7142 ret = 0;
7143 while ((CUR >= '0') && (CUR <= '9')) {
7144 ret = ret * 10 + (CUR - '0');
7145 ok = 1;
7146 NEXT;
7147 }
7148#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007149 if (CUR == '.') {
7150 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007151 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7152 XP_ERROR(XPATH_NUMBER_ERROR);
7153 }
7154 while ((CUR >= '0') && (CUR <= '9')) {
7155 mult /= 10;
7156 ret = ret + (CUR - '0') * mult;
7157 NEXT;
7158 }
Owen Taylor3473f882001-02-23 17:55:21 +00007159 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007160 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007161 NEXT;
7162 if (CUR == '-') {
7163 is_exponent_negative = 1;
7164 NEXT;
7165 }
7166 while ((CUR >= '0') && (CUR <= '9')) {
7167 exponent = exponent * 10 + (CUR - '0');
7168 NEXT;
7169 }
7170 if (is_exponent_negative)
7171 exponent = -exponent;
7172 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007173 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007174 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007175 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007176}
7177
7178/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007179 * xmlXPathParseLiteral:
7180 * @ctxt: the XPath Parser context
7181 *
7182 * Parse a Literal
7183 *
7184 * [29] Literal ::= '"' [^"]* '"'
7185 * | "'" [^']* "'"
7186 *
7187 * Returns the value found or NULL in case of error
7188 */
7189static xmlChar *
7190xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7191 const xmlChar *q;
7192 xmlChar *ret = NULL;
7193
7194 if (CUR == '"') {
7195 NEXT;
7196 q = CUR_PTR;
7197 while ((IS_CHAR(CUR)) && (CUR != '"'))
7198 NEXT;
7199 if (!IS_CHAR(CUR)) {
7200 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7201 } else {
7202 ret = xmlStrndup(q, CUR_PTR - q);
7203 NEXT;
7204 }
7205 } else if (CUR == '\'') {
7206 NEXT;
7207 q = CUR_PTR;
7208 while ((IS_CHAR(CUR)) && (CUR != '\''))
7209 NEXT;
7210 if (!IS_CHAR(CUR)) {
7211 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7212 } else {
7213 ret = xmlStrndup(q, CUR_PTR - q);
7214 NEXT;
7215 }
7216 } else {
7217 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7218 }
7219 return(ret);
7220}
7221
7222/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007223 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007224 * @ctxt: the XPath Parser context
7225 *
7226 * Parse a Literal and push it on the stack.
7227 *
7228 * [29] Literal ::= '"' [^"]* '"'
7229 * | "'" [^']* "'"
7230 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007231 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007232 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007233static void
7234xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007235 const xmlChar *q;
7236 xmlChar *ret = NULL;
7237
7238 if (CUR == '"') {
7239 NEXT;
7240 q = CUR_PTR;
7241 while ((IS_CHAR(CUR)) && (CUR != '"'))
7242 NEXT;
7243 if (!IS_CHAR(CUR)) {
7244 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7245 } else {
7246 ret = xmlStrndup(q, CUR_PTR - q);
7247 NEXT;
7248 }
7249 } else if (CUR == '\'') {
7250 NEXT;
7251 q = CUR_PTR;
7252 while ((IS_CHAR(CUR)) && (CUR != '\''))
7253 NEXT;
7254 if (!IS_CHAR(CUR)) {
7255 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7256 } else {
7257 ret = xmlStrndup(q, CUR_PTR - q);
7258 NEXT;
7259 }
7260 } else {
7261 XP_ERROR(XPATH_START_LITERAL_ERROR);
7262 }
7263 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007264 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7265 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007266 xmlFree(ret);
7267}
7268
7269/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007270 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007271 * @ctxt: the XPath Parser context
7272 *
7273 * Parse a VariableReference, evaluate it and push it on the stack.
7274 *
7275 * The variable bindings consist of a mapping from variable names
7276 * to variable values. The value of a variable is an object, which
7277 * of any of the types that are possible for the value of an expression,
7278 * and may also be of additional types not specified here.
7279 *
7280 * Early evaluation is possible since:
7281 * The variable bindings [...] used to evaluate a subexpression are
7282 * always the same as those used to evaluate the containing expression.
7283 *
7284 * [36] VariableReference ::= '$' QName
7285 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007286static void
7287xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007288 xmlChar *name;
7289 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007290
7291 SKIP_BLANKS;
7292 if (CUR != '$') {
7293 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7294 }
7295 NEXT;
7296 name = xmlXPathParseQName(ctxt, &prefix);
7297 if (name == NULL) {
7298 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7299 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007300 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007301 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7302 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007303 SKIP_BLANKS;
7304}
7305
7306/**
7307 * xmlXPathIsNodeType:
7308 * @ctxt: the XPath Parser context
7309 * @name: a name string
7310 *
7311 * Is the name given a NodeType one.
7312 *
7313 * [38] NodeType ::= 'comment'
7314 * | 'text'
7315 * | 'processing-instruction'
7316 * | 'node'
7317 *
7318 * Returns 1 if true 0 otherwise
7319 */
7320int
7321xmlXPathIsNodeType(const xmlChar *name) {
7322 if (name == NULL)
7323 return(0);
7324
Daniel Veillard1971ee22002-01-31 20:29:19 +00007325 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007326 return(1);
7327 if (xmlStrEqual(name, BAD_CAST "text"))
7328 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007329 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007330 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007331 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007332 return(1);
7333 return(0);
7334}
7335
7336/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007337 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007338 * @ctxt: the XPath Parser context
7339 *
7340 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7341 * [17] Argument ::= Expr
7342 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007343 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007344 * pushed on the stack
7345 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007346static void
7347xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007348 xmlChar *name;
7349 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007350 int nbargs = 0;
7351
7352 name = xmlXPathParseQName(ctxt, &prefix);
7353 if (name == NULL) {
7354 XP_ERROR(XPATH_EXPR_ERROR);
7355 }
7356 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007357#ifdef DEBUG_EXPR
7358 if (prefix == NULL)
7359 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7360 name);
7361 else
7362 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7363 prefix, name);
7364#endif
7365
Owen Taylor3473f882001-02-23 17:55:21 +00007366 if (CUR != '(') {
7367 XP_ERROR(XPATH_EXPR_ERROR);
7368 }
7369 NEXT;
7370 SKIP_BLANKS;
7371
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007372 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007373 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007374 int op1 = ctxt->comp->last;
7375 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007376 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007377 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007378 nbargs++;
7379 if (CUR == ')') break;
7380 if (CUR != ',') {
7381 XP_ERROR(XPATH_EXPR_ERROR);
7382 }
7383 NEXT;
7384 SKIP_BLANKS;
7385 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007386 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7387 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007388 NEXT;
7389 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007390}
7391
7392/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007393 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007394 * @ctxt: the XPath Parser context
7395 *
7396 * [15] PrimaryExpr ::= VariableReference
7397 * | '(' Expr ')'
7398 * | Literal
7399 * | Number
7400 * | FunctionCall
7401 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007402 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007403 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007404static void
7405xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007406 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007407 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007408 else if (CUR == '(') {
7409 NEXT;
7410 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007411 xmlXPathCompileExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007412 if (CUR != ')') {
7413 XP_ERROR(XPATH_EXPR_ERROR);
7414 }
7415 NEXT;
7416 SKIP_BLANKS;
Daniel Veillard01917aa2002-04-10 11:30:41 +00007417 } else if (IS_DIGIT(CUR) || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007418 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007419 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007420 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007421 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007422 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007423 }
7424 SKIP_BLANKS;
7425}
7426
7427/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007428 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007429 * @ctxt: the XPath Parser context
7430 *
7431 * [20] FilterExpr ::= PrimaryExpr
7432 * | FilterExpr Predicate
7433 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007434 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007435 * Square brackets are used to filter expressions in the same way that
7436 * they are used in location paths. It is an error if the expression to
7437 * be filtered does not evaluate to a node-set. The context node list
7438 * used for evaluating the expression in square brackets is the node-set
7439 * to be filtered listed in document order.
7440 */
7441
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007442static void
7443xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
7444 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007445 CHECK_ERROR;
7446 SKIP_BLANKS;
7447
7448 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007449 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00007450 SKIP_BLANKS;
7451 }
7452
7453
7454}
7455
7456/**
7457 * xmlXPathScanName:
7458 * @ctxt: the XPath Parser context
7459 *
7460 * Trickery: parse an XML name but without consuming the input flow
7461 * Needed to avoid insanity in the parser state.
7462 *
7463 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7464 * CombiningChar | Extender
7465 *
7466 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7467 *
7468 * [6] Names ::= Name (S Name)*
7469 *
7470 * Returns the Name parsed or NULL
7471 */
7472
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007473static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007474xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7475 xmlChar buf[XML_MAX_NAMELEN];
7476 int len = 0;
7477
7478 SKIP_BLANKS;
7479 if (!IS_LETTER(CUR) && (CUR != '_') &&
7480 (CUR != ':')) {
7481 return(NULL);
7482 }
7483
7484 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7485 (NXT(len) == '.') || (NXT(len) == '-') ||
7486 (NXT(len) == '_') || (NXT(len) == ':') ||
7487 (IS_COMBINING(NXT(len))) ||
7488 (IS_EXTENDER(NXT(len)))) {
7489 buf[len] = NXT(len);
7490 len++;
7491 if (len >= XML_MAX_NAMELEN) {
7492 xmlGenericError(xmlGenericErrorContext,
7493 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
7494 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7495 (NXT(len) == '.') || (NXT(len) == '-') ||
7496 (NXT(len) == '_') || (NXT(len) == ':') ||
7497 (IS_COMBINING(NXT(len))) ||
7498 (IS_EXTENDER(NXT(len))))
7499 len++;
7500 break;
7501 }
7502 }
7503 return(xmlStrndup(buf, len));
7504}
7505
7506/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007507 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007508 * @ctxt: the XPath Parser context
7509 *
7510 * [19] PathExpr ::= LocationPath
7511 * | FilterExpr
7512 * | FilterExpr '/' RelativeLocationPath
7513 * | FilterExpr '//' RelativeLocationPath
7514 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007515 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007516 * The / operator and // operators combine an arbitrary expression
7517 * and a relative location path. It is an error if the expression
7518 * does not evaluate to a node-set.
7519 * The / operator does composition in the same way as when / is
7520 * used in a location path. As in location paths, // is short for
7521 * /descendant-or-self::node()/.
7522 */
7523
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007524static void
7525xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007526 int lc = 1; /* Should we branch to LocationPath ? */
7527 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7528
7529 SKIP_BLANKS;
7530 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
Daniel Veillard01917aa2002-04-10 11:30:41 +00007531 (CUR == '\'') || (CUR == '"') || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00007532 lc = 0;
7533 } else if (CUR == '*') {
7534 /* relative or absolute location path */
7535 lc = 1;
7536 } else if (CUR == '/') {
7537 /* relative or absolute location path */
7538 lc = 1;
7539 } else if (CUR == '@') {
7540 /* relative abbreviated attribute location path */
7541 lc = 1;
7542 } else if (CUR == '.') {
7543 /* relative abbreviated attribute location path */
7544 lc = 1;
7545 } else {
7546 /*
7547 * Problem is finding if we have a name here whether it's:
7548 * - a nodetype
7549 * - a function call in which case it's followed by '('
7550 * - an axis in which case it's followed by ':'
7551 * - a element name
7552 * We do an a priori analysis here rather than having to
7553 * maintain parsed token content through the recursive function
7554 * calls. This looks uglier but makes the code quite easier to
7555 * read/write/debug.
7556 */
7557 SKIP_BLANKS;
7558 name = xmlXPathScanName(ctxt);
7559 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7560#ifdef DEBUG_STEP
7561 xmlGenericError(xmlGenericErrorContext,
7562 "PathExpr: Axis\n");
7563#endif
7564 lc = 1;
7565 xmlFree(name);
7566 } else if (name != NULL) {
7567 int len =xmlStrlen(name);
7568 int blank = 0;
7569
7570
7571 while (NXT(len) != 0) {
7572 if (NXT(len) == '/') {
7573 /* element name */
7574#ifdef DEBUG_STEP
7575 xmlGenericError(xmlGenericErrorContext,
7576 "PathExpr: AbbrRelLocation\n");
7577#endif
7578 lc = 1;
7579 break;
7580 } else if (IS_BLANK(NXT(len))) {
7581 /* skip to next */
7582 blank = 1;
7583 } else if (NXT(len) == ':') {
7584#ifdef DEBUG_STEP
7585 xmlGenericError(xmlGenericErrorContext,
7586 "PathExpr: AbbrRelLocation\n");
7587#endif
7588 lc = 1;
7589 break;
7590 } else if ((NXT(len) == '(')) {
7591 /* Note Type or Function */
7592 if (xmlXPathIsNodeType(name)) {
7593#ifdef DEBUG_STEP
7594 xmlGenericError(xmlGenericErrorContext,
7595 "PathExpr: Type search\n");
7596#endif
7597 lc = 1;
7598 } else {
7599#ifdef DEBUG_STEP
7600 xmlGenericError(xmlGenericErrorContext,
7601 "PathExpr: function call\n");
7602#endif
7603 lc = 0;
7604 }
7605 break;
7606 } else if ((NXT(len) == '[')) {
7607 /* element name */
7608#ifdef DEBUG_STEP
7609 xmlGenericError(xmlGenericErrorContext,
7610 "PathExpr: AbbrRelLocation\n");
7611#endif
7612 lc = 1;
7613 break;
7614 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
7615 (NXT(len) == '=')) {
7616 lc = 1;
7617 break;
7618 } else {
7619 lc = 1;
7620 break;
7621 }
7622 len++;
7623 }
7624 if (NXT(len) == 0) {
7625#ifdef DEBUG_STEP
7626 xmlGenericError(xmlGenericErrorContext,
7627 "PathExpr: AbbrRelLocation\n");
7628#endif
7629 /* element name */
7630 lc = 1;
7631 }
7632 xmlFree(name);
7633 } else {
7634 /* make sure all cases are covered explicitely */
7635 XP_ERROR(XPATH_EXPR_ERROR);
7636 }
7637 }
7638
7639 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007640 if (CUR == '/') {
7641 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
7642 } else {
7643 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007644 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007645 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007646 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007647 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007648 CHECK_ERROR;
7649 if ((CUR == '/') && (NXT(1) == '/')) {
7650 SKIP(2);
7651 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007652
7653 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7654 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
7655 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
7656
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007657 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007658 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007659 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007660 }
7661 }
7662 SKIP_BLANKS;
7663}
7664
7665/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007666 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007667 * @ctxt: the XPath Parser context
7668 *
7669 * [18] UnionExpr ::= PathExpr
7670 * | UnionExpr '|' PathExpr
7671 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007672 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007673 */
7674
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007675static void
7676xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
7677 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007678 CHECK_ERROR;
7679 SKIP_BLANKS;
7680 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007681 int op1 = ctxt->comp->last;
7682 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007683
7684 NEXT;
7685 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007686 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007687
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007688 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
7689
Owen Taylor3473f882001-02-23 17:55:21 +00007690 SKIP_BLANKS;
7691 }
Owen Taylor3473f882001-02-23 17:55:21 +00007692}
7693
7694/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007695 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007696 * @ctxt: the XPath Parser context
7697 *
7698 * [27] UnaryExpr ::= UnionExpr
7699 * | '-' UnaryExpr
7700 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007701 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007702 */
7703
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007704static void
7705xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007706 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007707 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007708
7709 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00007710 while (CUR == '-') {
7711 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007712 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007713 NEXT;
7714 SKIP_BLANKS;
7715 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007716
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007717 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007718 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007719 if (found) {
7720 if (minus)
7721 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
7722 else
7723 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007724 }
7725}
7726
7727/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007728 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007729 * @ctxt: the XPath Parser context
7730 *
7731 * [26] MultiplicativeExpr ::= UnaryExpr
7732 * | MultiplicativeExpr MultiplyOperator UnaryExpr
7733 * | MultiplicativeExpr 'div' UnaryExpr
7734 * | MultiplicativeExpr 'mod' UnaryExpr
7735 * [34] MultiplyOperator ::= '*'
7736 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007737 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007738 */
7739
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007740static void
7741xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
7742 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007743 CHECK_ERROR;
7744 SKIP_BLANKS;
7745 while ((CUR == '*') ||
7746 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
7747 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
7748 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007749 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007750
7751 if (CUR == '*') {
7752 op = 0;
7753 NEXT;
7754 } else if (CUR == 'd') {
7755 op = 1;
7756 SKIP(3);
7757 } else if (CUR == 'm') {
7758 op = 2;
7759 SKIP(3);
7760 }
7761 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007762 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007763 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007764 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007765 SKIP_BLANKS;
7766 }
7767}
7768
7769/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007770 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007771 * @ctxt: the XPath Parser context
7772 *
7773 * [25] AdditiveExpr ::= MultiplicativeExpr
7774 * | AdditiveExpr '+' MultiplicativeExpr
7775 * | AdditiveExpr '-' MultiplicativeExpr
7776 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007777 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007778 */
7779
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007780static void
7781xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007782
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007783 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007784 CHECK_ERROR;
7785 SKIP_BLANKS;
7786 while ((CUR == '+') || (CUR == '-')) {
7787 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007788 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007789
7790 if (CUR == '+') plus = 1;
7791 else plus = 0;
7792 NEXT;
7793 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007794 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007795 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007796 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007797 SKIP_BLANKS;
7798 }
7799}
7800
7801/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007802 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007803 * @ctxt: the XPath Parser context
7804 *
7805 * [24] RelationalExpr ::= AdditiveExpr
7806 * | RelationalExpr '<' AdditiveExpr
7807 * | RelationalExpr '>' AdditiveExpr
7808 * | RelationalExpr '<=' AdditiveExpr
7809 * | RelationalExpr '>=' AdditiveExpr
7810 *
7811 * A <= B > C is allowed ? Answer from James, yes with
7812 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
7813 * which is basically what got implemented.
7814 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007815 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00007816 * on the stack
7817 */
7818
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007819static void
7820xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
7821 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007822 CHECK_ERROR;
7823 SKIP_BLANKS;
7824 while ((CUR == '<') ||
7825 (CUR == '>') ||
7826 ((CUR == '<') && (NXT(1) == '=')) ||
7827 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007828 int inf, strict;
7829 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007830
7831 if (CUR == '<') inf = 1;
7832 else inf = 0;
7833 if (NXT(1) == '=') strict = 0;
7834 else strict = 1;
7835 NEXT;
7836 if (!strict) NEXT;
7837 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007838 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007839 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007840 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00007841 SKIP_BLANKS;
7842 }
7843}
7844
7845/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007846 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007847 * @ctxt: the XPath Parser context
7848 *
7849 * [23] EqualityExpr ::= RelationalExpr
7850 * | EqualityExpr '=' RelationalExpr
7851 * | EqualityExpr '!=' RelationalExpr
7852 *
7853 * A != B != C is allowed ? Answer from James, yes with
7854 * (RelationalExpr = RelationalExpr) = RelationalExpr
7855 * (RelationalExpr != RelationalExpr) != RelationalExpr
7856 * which is basically what got implemented.
7857 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007858 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007859 *
7860 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007861static void
7862xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
7863 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007864 CHECK_ERROR;
7865 SKIP_BLANKS;
7866 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007867 int eq;
7868 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007869
7870 if (CUR == '=') eq = 1;
7871 else eq = 0;
7872 NEXT;
7873 if (!eq) NEXT;
7874 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007875 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007876 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007877 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007878 SKIP_BLANKS;
7879 }
7880}
7881
7882/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007883 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007884 * @ctxt: the XPath Parser context
7885 *
7886 * [22] AndExpr ::= EqualityExpr
7887 * | AndExpr 'and' EqualityExpr
7888 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007889 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007890 *
7891 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007892static void
7893xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
7894 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007895 CHECK_ERROR;
7896 SKIP_BLANKS;
7897 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007898 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007899 SKIP(3);
7900 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007901 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007902 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007903 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007904 SKIP_BLANKS;
7905 }
7906}
7907
7908/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007909 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007910 * @ctxt: the XPath Parser context
7911 *
7912 * [14] Expr ::= OrExpr
7913 * [21] OrExpr ::= AndExpr
7914 * | OrExpr 'or' AndExpr
7915 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007916 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00007917 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007918static void
7919xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
7920 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007921 CHECK_ERROR;
7922 SKIP_BLANKS;
7923 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007924 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007925 SKIP(2);
7926 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007927 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007928 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007929 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
7930 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00007931 SKIP_BLANKS;
7932 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007933 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
7934 /* more ops could be optimized too */
7935 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
7936 }
Owen Taylor3473f882001-02-23 17:55:21 +00007937}
7938
7939/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007940 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00007941 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007942 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00007943 *
7944 * [8] Predicate ::= '[' PredicateExpr ']'
7945 * [9] PredicateExpr ::= Expr
7946 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007947 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00007948 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007949static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007950xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007951 int op1 = ctxt->comp->last;
7952
7953 SKIP_BLANKS;
7954 if (CUR != '[') {
7955 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7956 }
7957 NEXT;
7958 SKIP_BLANKS;
7959
7960 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007961 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007962 CHECK_ERROR;
7963
7964 if (CUR != ']') {
7965 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7966 }
7967
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007968 if (filter)
7969 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
7970 else
7971 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007972
7973 NEXT;
7974 SKIP_BLANKS;
7975}
7976
7977/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007978 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00007979 * @ctxt: the XPath Parser context
7980 * @test: pointer to a xmlXPathTestVal
7981 * @type: pointer to a xmlXPathTypeVal
7982 * @prefix: placeholder for a possible name prefix
7983 *
7984 * [7] NodeTest ::= NameTest
7985 * | NodeType '(' ')'
7986 * | 'processing-instruction' '(' Literal ')'
7987 *
7988 * [37] NameTest ::= '*'
7989 * | NCName ':' '*'
7990 * | QName
7991 * [38] NodeType ::= 'comment'
7992 * | 'text'
7993 * | 'processing-instruction'
7994 * | 'node'
7995 *
7996 * Returns the name found and update @test, @type and @prefix appropriately
7997 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007998static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007999xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8000 xmlXPathTypeVal *type, const xmlChar **prefix,
8001 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008002 int blanks;
8003
8004 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8005 STRANGE;
8006 return(NULL);
8007 }
8008 *type = 0;
8009 *test = 0;
8010 *prefix = NULL;
8011 SKIP_BLANKS;
8012
8013 if ((name == NULL) && (CUR == '*')) {
8014 /*
8015 * All elements
8016 */
8017 NEXT;
8018 *test = NODE_TEST_ALL;
8019 return(NULL);
8020 }
8021
8022 if (name == NULL)
8023 name = xmlXPathParseNCName(ctxt);
8024 if (name == NULL) {
8025 XP_ERROR0(XPATH_EXPR_ERROR);
8026 }
8027
8028 blanks = IS_BLANK(CUR);
8029 SKIP_BLANKS;
8030 if (CUR == '(') {
8031 NEXT;
8032 /*
8033 * NodeType or PI search
8034 */
8035 if (xmlStrEqual(name, BAD_CAST "comment"))
8036 *type = NODE_TYPE_COMMENT;
8037 else if (xmlStrEqual(name, BAD_CAST "node"))
8038 *type = NODE_TYPE_NODE;
8039 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8040 *type = NODE_TYPE_PI;
8041 else if (xmlStrEqual(name, BAD_CAST "text"))
8042 *type = NODE_TYPE_TEXT;
8043 else {
8044 if (name != NULL)
8045 xmlFree(name);
8046 XP_ERROR0(XPATH_EXPR_ERROR);
8047 }
8048
8049 *test = NODE_TEST_TYPE;
8050
8051 SKIP_BLANKS;
8052 if (*type == NODE_TYPE_PI) {
8053 /*
8054 * Specific case: search a PI by name.
8055 */
Owen Taylor3473f882001-02-23 17:55:21 +00008056 if (name != NULL)
8057 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008058 name = NULL;
8059 if (CUR != ')') {
8060 name = xmlXPathParseLiteral(ctxt);
8061 CHECK_ERROR 0;
8062 SKIP_BLANKS;
8063 }
Owen Taylor3473f882001-02-23 17:55:21 +00008064 }
8065 if (CUR != ')') {
8066 if (name != NULL)
8067 xmlFree(name);
8068 XP_ERROR0(XPATH_UNCLOSED_ERROR);
8069 }
8070 NEXT;
8071 return(name);
8072 }
8073 *test = NODE_TEST_NAME;
8074 if ((!blanks) && (CUR == ':')) {
8075 NEXT;
8076
8077 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008078 * Since currently the parser context don't have a
8079 * namespace list associated:
8080 * The namespace name for this prefix can be computed
8081 * only at evaluation time. The compilation is done
8082 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008083 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008084#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008085 *prefix = xmlXPathNsLookup(ctxt->context, name);
8086 if (name != NULL)
8087 xmlFree(name);
8088 if (*prefix == NULL) {
8089 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8090 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008091#else
8092 *prefix = name;
8093#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008094
8095 if (CUR == '*') {
8096 /*
8097 * All elements
8098 */
8099 NEXT;
8100 *test = NODE_TEST_ALL;
8101 return(NULL);
8102 }
8103
8104 name = xmlXPathParseNCName(ctxt);
8105 if (name == NULL) {
8106 XP_ERROR0(XPATH_EXPR_ERROR);
8107 }
8108 }
8109 return(name);
8110}
8111
8112/**
8113 * xmlXPathIsAxisName:
8114 * @name: a preparsed name token
8115 *
8116 * [6] AxisName ::= 'ancestor'
8117 * | 'ancestor-or-self'
8118 * | 'attribute'
8119 * | 'child'
8120 * | 'descendant'
8121 * | 'descendant-or-self'
8122 * | 'following'
8123 * | 'following-sibling'
8124 * | 'namespace'
8125 * | 'parent'
8126 * | 'preceding'
8127 * | 'preceding-sibling'
8128 * | 'self'
8129 *
8130 * Returns the axis or 0
8131 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008132static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008133xmlXPathIsAxisName(const xmlChar *name) {
8134 xmlXPathAxisVal ret = 0;
8135 switch (name[0]) {
8136 case 'a':
8137 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8138 ret = AXIS_ANCESTOR;
8139 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8140 ret = AXIS_ANCESTOR_OR_SELF;
8141 if (xmlStrEqual(name, BAD_CAST "attribute"))
8142 ret = AXIS_ATTRIBUTE;
8143 break;
8144 case 'c':
8145 if (xmlStrEqual(name, BAD_CAST "child"))
8146 ret = AXIS_CHILD;
8147 break;
8148 case 'd':
8149 if (xmlStrEqual(name, BAD_CAST "descendant"))
8150 ret = AXIS_DESCENDANT;
8151 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8152 ret = AXIS_DESCENDANT_OR_SELF;
8153 break;
8154 case 'f':
8155 if (xmlStrEqual(name, BAD_CAST "following"))
8156 ret = AXIS_FOLLOWING;
8157 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8158 ret = AXIS_FOLLOWING_SIBLING;
8159 break;
8160 case 'n':
8161 if (xmlStrEqual(name, BAD_CAST "namespace"))
8162 ret = AXIS_NAMESPACE;
8163 break;
8164 case 'p':
8165 if (xmlStrEqual(name, BAD_CAST "parent"))
8166 ret = AXIS_PARENT;
8167 if (xmlStrEqual(name, BAD_CAST "preceding"))
8168 ret = AXIS_PRECEDING;
8169 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8170 ret = AXIS_PRECEDING_SIBLING;
8171 break;
8172 case 's':
8173 if (xmlStrEqual(name, BAD_CAST "self"))
8174 ret = AXIS_SELF;
8175 break;
8176 }
8177 return(ret);
8178}
8179
8180/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008181 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008182 * @ctxt: the XPath Parser context
8183 *
8184 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8185 * | AbbreviatedStep
8186 *
8187 * [12] AbbreviatedStep ::= '.' | '..'
8188 *
8189 * [5] AxisSpecifier ::= AxisName '::'
8190 * | AbbreviatedAxisSpecifier
8191 *
8192 * [13] AbbreviatedAxisSpecifier ::= '@'?
8193 *
8194 * Modified for XPtr range support as:
8195 *
8196 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8197 * | AbbreviatedStep
8198 * | 'range-to' '(' Expr ')' Predicate*
8199 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008200 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008201 * A location step of . is short for self::node(). This is
8202 * particularly useful in conjunction with //. For example, the
8203 * location path .//para is short for
8204 * self::node()/descendant-or-self::node()/child::para
8205 * and so will select all para descendant elements of the context
8206 * node.
8207 * Similarly, a location step of .. is short for parent::node().
8208 * For example, ../title is short for parent::node()/child::title
8209 * and so will select the title children of the parent of the context
8210 * node.
8211 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008212static void
8213xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008214#ifdef LIBXML_XPTR_ENABLED
8215 int rangeto = 0;
8216 int op2 = -1;
8217#endif
8218
Owen Taylor3473f882001-02-23 17:55:21 +00008219 SKIP_BLANKS;
8220 if ((CUR == '.') && (NXT(1) == '.')) {
8221 SKIP(2);
8222 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008223 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8224 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008225 } else if (CUR == '.') {
8226 NEXT;
8227 SKIP_BLANKS;
8228 } else {
8229 xmlChar *name = NULL;
8230 const xmlChar *prefix = NULL;
8231 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008232 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008233 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008234 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008235
8236 /*
8237 * The modification needed for XPointer change to the production
8238 */
8239#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008240 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008241 name = xmlXPathParseNCName(ctxt);
8242 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008243 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008244 xmlFree(name);
8245 SKIP_BLANKS;
8246 if (CUR != '(') {
8247 XP_ERROR(XPATH_EXPR_ERROR);
8248 }
8249 NEXT;
8250 SKIP_BLANKS;
8251
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008252 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008253 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008254 CHECK_ERROR;
8255
8256 SKIP_BLANKS;
8257 if (CUR != ')') {
8258 XP_ERROR(XPATH_EXPR_ERROR);
8259 }
8260 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008261 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008262 goto eval_predicates;
8263 }
8264 }
8265#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008266 if (CUR == '*') {
8267 axis = AXIS_CHILD;
8268 } else {
8269 if (name == NULL)
8270 name = xmlXPathParseNCName(ctxt);
8271 if (name != NULL) {
8272 axis = xmlXPathIsAxisName(name);
8273 if (axis != 0) {
8274 SKIP_BLANKS;
8275 if ((CUR == ':') && (NXT(1) == ':')) {
8276 SKIP(2);
8277 xmlFree(name);
8278 name = NULL;
8279 } else {
8280 /* an element name can conflict with an axis one :-\ */
8281 axis = AXIS_CHILD;
8282 }
Owen Taylor3473f882001-02-23 17:55:21 +00008283 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008284 axis = AXIS_CHILD;
8285 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008286 } else if (CUR == '@') {
8287 NEXT;
8288 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008289 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008290 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008291 }
Owen Taylor3473f882001-02-23 17:55:21 +00008292 }
8293
8294 CHECK_ERROR;
8295
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008296 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008297 if (test == 0)
8298 return;
8299
8300#ifdef DEBUG_STEP
8301 xmlGenericError(xmlGenericErrorContext,
8302 "Basis : computing new set\n");
8303#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008304
Owen Taylor3473f882001-02-23 17:55:21 +00008305#ifdef DEBUG_STEP
8306 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008307 if (ctxt->value == NULL)
8308 xmlGenericError(xmlGenericErrorContext, "no value\n");
8309 else if (ctxt->value->nodesetval == NULL)
8310 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8311 else
8312 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008313#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008314
8315eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008316 op1 = ctxt->comp->last;
8317 ctxt->comp->last = -1;
8318
Owen Taylor3473f882001-02-23 17:55:21 +00008319 SKIP_BLANKS;
8320 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008321 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008322 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008323
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008324#ifdef LIBXML_XPTR_ENABLED
8325 if (rangeto) {
8326 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8327 } else
8328#endif
8329 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8330 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008331
Owen Taylor3473f882001-02-23 17:55:21 +00008332 }
8333#ifdef DEBUG_STEP
8334 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008335 if (ctxt->value == NULL)
8336 xmlGenericError(xmlGenericErrorContext, "no value\n");
8337 else if (ctxt->value->nodesetval == NULL)
8338 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8339 else
8340 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8341 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008342#endif
8343}
8344
8345/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008346 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008347 * @ctxt: the XPath Parser context
8348 *
8349 * [3] RelativeLocationPath ::= Step
8350 * | RelativeLocationPath '/' Step
8351 * | AbbreviatedRelativeLocationPath
8352 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8353 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008354 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008355 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008356static void
Owen Taylor3473f882001-02-23 17:55:21 +00008357#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008358xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008359#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008360xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008361#endif
8362(xmlXPathParserContextPtr ctxt) {
8363 SKIP_BLANKS;
8364 if ((CUR == '/') && (NXT(1) == '/')) {
8365 SKIP(2);
8366 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008367 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8368 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008369 } else if (CUR == '/') {
8370 NEXT;
8371 SKIP_BLANKS;
8372 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008373 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008374 SKIP_BLANKS;
8375 while (CUR == '/') {
8376 if ((CUR == '/') && (NXT(1) == '/')) {
8377 SKIP(2);
8378 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008379 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008380 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008381 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008382 } else if (CUR == '/') {
8383 NEXT;
8384 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008385 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008386 }
8387 SKIP_BLANKS;
8388 }
8389}
8390
8391/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008392 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008393 * @ctxt: the XPath Parser context
8394 *
8395 * [1] LocationPath ::= RelativeLocationPath
8396 * | AbsoluteLocationPath
8397 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8398 * | AbbreviatedAbsoluteLocationPath
8399 * [10] AbbreviatedAbsoluteLocationPath ::=
8400 * '//' RelativeLocationPath
8401 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008402 * Compile a location path
8403 *
Owen Taylor3473f882001-02-23 17:55:21 +00008404 * // is short for /descendant-or-self::node()/. For example,
8405 * //para is short for /descendant-or-self::node()/child::para and
8406 * so will select any para element in the document (even a para element
8407 * that is a document element will be selected by //para since the
8408 * document element node is a child of the root node); div//para is
8409 * short for div/descendant-or-self::node()/child::para and so will
8410 * select all para descendants of div children.
8411 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008412static void
8413xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008414 SKIP_BLANKS;
8415 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008416 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008417 } else {
8418 while (CUR == '/') {
8419 if ((CUR == '/') && (NXT(1) == '/')) {
8420 SKIP(2);
8421 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008422 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8423 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008424 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008425 } else if (CUR == '/') {
8426 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008427 SKIP_BLANKS;
8428 if ((CUR != 0 ) &&
8429 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
8430 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008431 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008432 }
8433 }
8434 }
8435}
8436
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008437/************************************************************************
8438 * *
8439 * XPath precompiled expression evaluation *
8440 * *
8441 ************************************************************************/
8442
Daniel Veillardf06307e2001-07-03 10:35:50 +00008443static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008444xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8445
8446/**
8447 * xmlXPathNodeCollectAndTest:
8448 * @ctxt: the XPath Parser context
8449 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008450 * @first: pointer to the first element in document order
8451 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008452 *
8453 * This is the function implementing a step: based on the current list
8454 * of nodes, it builds up a new list, looking at all nodes under that
8455 * axis and selecting them it also do the predicate filtering
8456 *
8457 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00008458 *
8459 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008460 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008461static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008462xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008463 xmlXPathStepOpPtr op,
8464 xmlNodePtr * first, xmlNodePtr * last)
8465{
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008466 xmlXPathAxisVal axis = op->value;
8467 xmlXPathTestVal test = op->value2;
8468 xmlXPathTypeVal type = op->value3;
8469 const xmlChar *prefix = op->value4;
8470 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008471 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008472
8473#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008474 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008475#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008476 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008477 xmlNodeSetPtr ret, list;
8478 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008479 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00008480 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008481 xmlNodePtr cur = NULL;
8482 xmlXPathObjectPtr obj;
8483 xmlNodeSetPtr nodelist;
8484 xmlNodePtr tmp;
8485
Daniel Veillardf06307e2001-07-03 10:35:50 +00008486 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008487 obj = valuePop(ctxt);
8488 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00008489 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008490 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008491 URI = xmlXPathNsLookup(ctxt->context, prefix);
8492 if (URI == NULL)
8493 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008494 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008495#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008496 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008497#endif
8498 switch (axis) {
8499 case AXIS_ANCESTOR:
8500#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008501 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008502#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008503 first = NULL;
8504 next = xmlXPathNextAncestor;
8505 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008506 case AXIS_ANCESTOR_OR_SELF:
8507#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008508 xmlGenericError(xmlGenericErrorContext,
8509 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008510#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008511 first = NULL;
8512 next = xmlXPathNextAncestorOrSelf;
8513 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008514 case AXIS_ATTRIBUTE:
8515#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008516 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008517#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008518 first = NULL;
8519 last = NULL;
8520 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00008521 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008522 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008523 case AXIS_CHILD:
8524#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008525 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008526#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008527 last = NULL;
8528 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00008529 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008530 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008531 case AXIS_DESCENDANT:
8532#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008533 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008534#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008535 last = NULL;
8536 next = xmlXPathNextDescendant;
8537 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008538 case AXIS_DESCENDANT_OR_SELF:
8539#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008540 xmlGenericError(xmlGenericErrorContext,
8541 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008542#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008543 last = NULL;
8544 next = xmlXPathNextDescendantOrSelf;
8545 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008546 case AXIS_FOLLOWING:
8547#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008548 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008549#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008550 last = NULL;
8551 next = xmlXPathNextFollowing;
8552 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008553 case AXIS_FOLLOWING_SIBLING:
8554#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008555 xmlGenericError(xmlGenericErrorContext,
8556 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008557#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008558 last = NULL;
8559 next = xmlXPathNextFollowingSibling;
8560 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008561 case AXIS_NAMESPACE:
8562#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008563 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008564#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008565 first = NULL;
8566 last = NULL;
8567 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00008568 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008569 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008570 case AXIS_PARENT:
8571#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008572 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008573#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008574 first = NULL;
8575 next = xmlXPathNextParent;
8576 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008577 case AXIS_PRECEDING:
8578#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008579 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008580#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008581 first = NULL;
8582 next = xmlXPathNextPrecedingInternal;
8583 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008584 case AXIS_PRECEDING_SIBLING:
8585#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008586 xmlGenericError(xmlGenericErrorContext,
8587 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008588#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008589 first = NULL;
8590 next = xmlXPathNextPrecedingSibling;
8591 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008592 case AXIS_SELF:
8593#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008594 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008595#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008596 first = NULL;
8597 last = NULL;
8598 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00008599 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008600 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008601 }
8602 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008603 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008604
8605 nodelist = obj->nodesetval;
8606 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008607 xmlXPathFreeObject(obj);
8608 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8609 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008610 }
8611 addNode = xmlXPathNodeSetAddUnique;
8612 ret = NULL;
8613#ifdef DEBUG_STEP
8614 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008615 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008616 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008617 case NODE_TEST_NONE:
8618 xmlGenericError(xmlGenericErrorContext,
8619 " searching for none !!!\n");
8620 break;
8621 case NODE_TEST_TYPE:
8622 xmlGenericError(xmlGenericErrorContext,
8623 " searching for type %d\n", type);
8624 break;
8625 case NODE_TEST_PI:
8626 xmlGenericError(xmlGenericErrorContext,
8627 " searching for PI !!!\n");
8628 break;
8629 case NODE_TEST_ALL:
8630 xmlGenericError(xmlGenericErrorContext,
8631 " searching for *\n");
8632 break;
8633 case NODE_TEST_NS:
8634 xmlGenericError(xmlGenericErrorContext,
8635 " searching for namespace %s\n",
8636 prefix);
8637 break;
8638 case NODE_TEST_NAME:
8639 xmlGenericError(xmlGenericErrorContext,
8640 " searching for name %s\n", name);
8641 if (prefix != NULL)
8642 xmlGenericError(xmlGenericErrorContext,
8643 " with namespace %s\n", prefix);
8644 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008645 }
8646 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8647#endif
8648 /*
8649 * 2.3 Node Tests
8650 * - For the attribute axis, the principal node type is attribute.
8651 * - For the namespace axis, the principal node type is namespace.
8652 * - For other axes, the principal node type is element.
8653 *
8654 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008655 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008656 * select all element children of the context node
8657 */
8658 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008659 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008660 ctxt->context->node = nodelist->nodeTab[i];
8661
Daniel Veillardf06307e2001-07-03 10:35:50 +00008662 cur = NULL;
8663 list = xmlXPathNodeSetCreate(NULL);
8664 do {
8665 cur = next(ctxt, cur);
8666 if (cur == NULL)
8667 break;
8668 if ((first != NULL) && (*first == cur))
8669 break;
8670 if (((t % 256) == 0) &&
8671 (first != NULL) && (*first != NULL) &&
8672 (xmlXPathCmpNodes(*first, cur) >= 0))
8673 break;
8674 if ((last != NULL) && (*last == cur))
8675 break;
8676 if (((t % 256) == 0) &&
8677 (last != NULL) && (*last != NULL) &&
8678 (xmlXPathCmpNodes(cur, *last) >= 0))
8679 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008680 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008681#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008682 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
8683#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008684 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008685 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008686 ctxt->context->node = tmp;
8687 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008688 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008689 if ((cur->type == type) ||
8690 ((type == NODE_TYPE_NODE) &&
8691 ((cur->type == XML_DOCUMENT_NODE) ||
8692 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8693 (cur->type == XML_ELEMENT_NODE) ||
8694 (cur->type == XML_PI_NODE) ||
8695 (cur->type == XML_COMMENT_NODE) ||
8696 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00008697 (cur->type == XML_TEXT_NODE))) ||
8698 ((type == NODE_TYPE_TEXT) &&
8699 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008700#ifdef DEBUG_STEP
8701 n++;
8702#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008703 addNode(list, cur);
8704 }
8705 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008706 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008707 if (cur->type == XML_PI_NODE) {
8708 if ((name != NULL) &&
8709 (!xmlStrEqual(name, cur->name)))
8710 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008711#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008712 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008713#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008714 addNode(list, cur);
8715 }
8716 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008717 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008718 if (axis == AXIS_ATTRIBUTE) {
8719 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008720#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008721 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008722#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008723 addNode(list, cur);
8724 }
8725 } else if (axis == AXIS_NAMESPACE) {
8726 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008727#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008728 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008729#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008730 xmlXPathNodeSetAddNs(list, ctxt->context->node,
8731 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008732 }
8733 } else {
8734 if (cur->type == XML_ELEMENT_NODE) {
8735 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008736#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008737 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008738#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008739 addNode(list, cur);
8740 } else if ((cur->ns != NULL) &&
8741 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008742#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008743 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008744#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008745 addNode(list, cur);
8746 }
8747 }
8748 }
8749 break;
8750 case NODE_TEST_NS:{
8751 TODO;
8752 break;
8753 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008754 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008755 switch (cur->type) {
8756 case XML_ELEMENT_NODE:
8757 if (xmlStrEqual(name, cur->name)) {
8758 if (prefix == NULL) {
8759 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008760#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008761 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008762#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008763 addNode(list, cur);
8764 }
8765 } else {
8766 if ((cur->ns != NULL) &&
8767 (xmlStrEqual(URI,
8768 cur->ns->href))) {
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 }
8775 }
8776 break;
8777 case XML_ATTRIBUTE_NODE:{
8778 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008779
Daniel Veillardf06307e2001-07-03 10:35:50 +00008780 if (xmlStrEqual(name, attr->name)) {
8781 if (prefix == NULL) {
8782 if ((attr->ns == NULL) ||
8783 (attr->ns->prefix == NULL)) {
8784#ifdef DEBUG_STEP
8785 n++;
8786#endif
8787 addNode(list,
8788 (xmlNodePtr) attr);
8789 }
8790 } else {
8791 if ((attr->ns != NULL) &&
8792 (xmlStrEqual(URI,
8793 attr->ns->
8794 href))) {
8795#ifdef DEBUG_STEP
8796 n++;
8797#endif
8798 addNode(list,
8799 (xmlNodePtr) attr);
8800 }
8801 }
8802 }
8803 break;
8804 }
8805 case XML_NAMESPACE_DECL:
8806 if (cur->type == XML_NAMESPACE_DECL) {
8807 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008808
Daniel Veillardf06307e2001-07-03 10:35:50 +00008809 if ((ns->prefix != NULL) && (name != NULL)
8810 && (xmlStrEqual(ns->prefix, name))) {
8811#ifdef DEBUG_STEP
8812 n++;
8813#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008814 xmlXPathNodeSetAddNs(list,
8815 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008816 }
8817 }
8818 break;
8819 default:
8820 break;
8821 }
8822 break;
8823 break;
8824 }
8825 } while (cur != NULL);
8826
8827 /*
8828 * If there is some predicate filtering do it now
8829 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00008830 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008831 xmlXPathObjectPtr obj2;
8832
8833 valuePush(ctxt, xmlXPathWrapNodeSet(list));
8834 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
8835 CHECK_TYPE0(XPATH_NODESET);
8836 obj2 = valuePop(ctxt);
8837 list = obj2->nodesetval;
8838 obj2->nodesetval = NULL;
8839 xmlXPathFreeObject(obj2);
8840 }
8841 if (ret == NULL) {
8842 ret = list;
8843 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00008844 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008845 xmlXPathFreeNodeSet(list);
8846 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008847 }
8848 ctxt->context->node = tmp;
8849#ifdef DEBUG_STEP
8850 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008851 "\nExamined %d nodes, found %d nodes at that step\n",
8852 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008853#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008854 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00008855 if ((obj->boolval) && (obj->user != NULL)) {
8856 ctxt->value->boolval = 1;
8857 ctxt->value->user = obj->user;
8858 obj->user = NULL;
8859 obj->boolval = 0;
8860 }
8861 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008862 return(t);
8863}
8864
8865/**
8866 * xmlXPathNodeCollectAndTestNth:
8867 * @ctxt: the XPath Parser context
8868 * @op: the XPath precompiled step operation
8869 * @indx: the index to collect
8870 * @first: pointer to the first element in document order
8871 * @last: pointer to the last element in document order
8872 *
8873 * This is the function implementing a step: based on the current list
8874 * of nodes, it builds up a new list, looking at all nodes under that
8875 * axis and selecting them it also do the predicate filtering
8876 *
8877 * Pushes the new NodeSet resulting from the search.
8878 * Returns the number of node traversed
8879 */
8880static int
8881xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
8882 xmlXPathStepOpPtr op, int indx,
8883 xmlNodePtr * first, xmlNodePtr * last)
8884{
8885 xmlXPathAxisVal axis = op->value;
8886 xmlXPathTestVal test = op->value2;
8887 xmlXPathTypeVal type = op->value3;
8888 const xmlChar *prefix = op->value4;
8889 const xmlChar *name = op->value5;
8890 const xmlChar *URI = NULL;
8891 int n = 0, t = 0;
8892
8893 int i;
8894 xmlNodeSetPtr list;
8895 xmlXPathTraversalFunction next = NULL;
8896 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
8897 xmlNodePtr cur = NULL;
8898 xmlXPathObjectPtr obj;
8899 xmlNodeSetPtr nodelist;
8900 xmlNodePtr tmp;
8901
8902 CHECK_TYPE0(XPATH_NODESET);
8903 obj = valuePop(ctxt);
8904 addNode = xmlXPathNodeSetAdd;
8905 if (prefix != NULL) {
8906 URI = xmlXPathNsLookup(ctxt->context, prefix);
8907 if (URI == NULL)
8908 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8909 }
8910#ifdef DEBUG_STEP_NTH
8911 xmlGenericError(xmlGenericErrorContext, "new step : ");
8912 if (first != NULL) {
8913 if (*first != NULL)
8914 xmlGenericError(xmlGenericErrorContext, "first = %s ",
8915 (*first)->name);
8916 else
8917 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
8918 }
8919 if (last != NULL) {
8920 if (*last != NULL)
8921 xmlGenericError(xmlGenericErrorContext, "last = %s ",
8922 (*last)->name);
8923 else
8924 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
8925 }
8926#endif
8927 switch (axis) {
8928 case AXIS_ANCESTOR:
8929#ifdef DEBUG_STEP_NTH
8930 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
8931#endif
8932 first = NULL;
8933 next = xmlXPathNextAncestor;
8934 break;
8935 case AXIS_ANCESTOR_OR_SELF:
8936#ifdef DEBUG_STEP_NTH
8937 xmlGenericError(xmlGenericErrorContext,
8938 "axis 'ancestors-or-self' ");
8939#endif
8940 first = NULL;
8941 next = xmlXPathNextAncestorOrSelf;
8942 break;
8943 case AXIS_ATTRIBUTE:
8944#ifdef DEBUG_STEP_NTH
8945 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
8946#endif
8947 first = NULL;
8948 last = NULL;
8949 next = xmlXPathNextAttribute;
8950 break;
8951 case AXIS_CHILD:
8952#ifdef DEBUG_STEP_NTH
8953 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
8954#endif
8955 last = NULL;
8956 next = xmlXPathNextChild;
8957 break;
8958 case AXIS_DESCENDANT:
8959#ifdef DEBUG_STEP_NTH
8960 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
8961#endif
8962 last = NULL;
8963 next = xmlXPathNextDescendant;
8964 break;
8965 case AXIS_DESCENDANT_OR_SELF:
8966#ifdef DEBUG_STEP_NTH
8967 xmlGenericError(xmlGenericErrorContext,
8968 "axis 'descendant-or-self' ");
8969#endif
8970 last = NULL;
8971 next = xmlXPathNextDescendantOrSelf;
8972 break;
8973 case AXIS_FOLLOWING:
8974#ifdef DEBUG_STEP_NTH
8975 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
8976#endif
8977 last = NULL;
8978 next = xmlXPathNextFollowing;
8979 break;
8980 case AXIS_FOLLOWING_SIBLING:
8981#ifdef DEBUG_STEP_NTH
8982 xmlGenericError(xmlGenericErrorContext,
8983 "axis 'following-siblings' ");
8984#endif
8985 last = NULL;
8986 next = xmlXPathNextFollowingSibling;
8987 break;
8988 case AXIS_NAMESPACE:
8989#ifdef DEBUG_STEP_NTH
8990 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
8991#endif
8992 last = NULL;
8993 first = NULL;
8994 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
8995 break;
8996 case AXIS_PARENT:
8997#ifdef DEBUG_STEP_NTH
8998 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
8999#endif
9000 first = NULL;
9001 next = xmlXPathNextParent;
9002 break;
9003 case AXIS_PRECEDING:
9004#ifdef DEBUG_STEP_NTH
9005 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9006#endif
9007 first = NULL;
9008 next = xmlXPathNextPrecedingInternal;
9009 break;
9010 case AXIS_PRECEDING_SIBLING:
9011#ifdef DEBUG_STEP_NTH
9012 xmlGenericError(xmlGenericErrorContext,
9013 "axis 'preceding-sibling' ");
9014#endif
9015 first = NULL;
9016 next = xmlXPathNextPrecedingSibling;
9017 break;
9018 case AXIS_SELF:
9019#ifdef DEBUG_STEP_NTH
9020 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9021#endif
9022 first = NULL;
9023 last = NULL;
9024 next = xmlXPathNextSelf;
9025 break;
9026 }
9027 if (next == NULL)
9028 return(0);
9029
9030 nodelist = obj->nodesetval;
9031 if (nodelist == NULL) {
9032 xmlXPathFreeObject(obj);
9033 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9034 return(0);
9035 }
9036 addNode = xmlXPathNodeSetAddUnique;
9037#ifdef DEBUG_STEP_NTH
9038 xmlGenericError(xmlGenericErrorContext,
9039 " context contains %d nodes\n", nodelist->nodeNr);
9040 switch (test) {
9041 case NODE_TEST_NONE:
9042 xmlGenericError(xmlGenericErrorContext,
9043 " searching for none !!!\n");
9044 break;
9045 case NODE_TEST_TYPE:
9046 xmlGenericError(xmlGenericErrorContext,
9047 " searching for type %d\n", type);
9048 break;
9049 case NODE_TEST_PI:
9050 xmlGenericError(xmlGenericErrorContext,
9051 " searching for PI !!!\n");
9052 break;
9053 case NODE_TEST_ALL:
9054 xmlGenericError(xmlGenericErrorContext,
9055 " searching for *\n");
9056 break;
9057 case NODE_TEST_NS:
9058 xmlGenericError(xmlGenericErrorContext,
9059 " searching for namespace %s\n",
9060 prefix);
9061 break;
9062 case NODE_TEST_NAME:
9063 xmlGenericError(xmlGenericErrorContext,
9064 " searching for name %s\n", name);
9065 if (prefix != NULL)
9066 xmlGenericError(xmlGenericErrorContext,
9067 " with namespace %s\n", prefix);
9068 break;
9069 }
9070 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9071#endif
9072 /*
9073 * 2.3 Node Tests
9074 * - For the attribute axis, the principal node type is attribute.
9075 * - For the namespace axis, the principal node type is namespace.
9076 * - For other axes, the principal node type is element.
9077 *
9078 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009079 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009080 * select all element children of the context node
9081 */
9082 tmp = ctxt->context->node;
9083 list = xmlXPathNodeSetCreate(NULL);
9084 for (i = 0; i < nodelist->nodeNr; i++) {
9085 ctxt->context->node = nodelist->nodeTab[i];
9086
9087 cur = NULL;
9088 n = 0;
9089 do {
9090 cur = next(ctxt, cur);
9091 if (cur == NULL)
9092 break;
9093 if ((first != NULL) && (*first == cur))
9094 break;
9095 if (((t % 256) == 0) &&
9096 (first != NULL) && (*first != NULL) &&
9097 (xmlXPathCmpNodes(*first, cur) >= 0))
9098 break;
9099 if ((last != NULL) && (*last == cur))
9100 break;
9101 if (((t % 256) == 0) &&
9102 (last != NULL) && (*last != NULL) &&
9103 (xmlXPathCmpNodes(cur, *last) >= 0))
9104 break;
9105 t++;
9106 switch (test) {
9107 case NODE_TEST_NONE:
9108 ctxt->context->node = tmp;
9109 STRANGE return(0);
9110 case NODE_TEST_TYPE:
9111 if ((cur->type == type) ||
9112 ((type == NODE_TYPE_NODE) &&
9113 ((cur->type == XML_DOCUMENT_NODE) ||
9114 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9115 (cur->type == XML_ELEMENT_NODE) ||
9116 (cur->type == XML_PI_NODE) ||
9117 (cur->type == XML_COMMENT_NODE) ||
9118 (cur->type == XML_CDATA_SECTION_NODE) ||
9119 (cur->type == XML_TEXT_NODE)))) {
9120 n++;
9121 if (n == indx)
9122 addNode(list, cur);
9123 }
9124 break;
9125 case NODE_TEST_PI:
9126 if (cur->type == XML_PI_NODE) {
9127 if ((name != NULL) &&
9128 (!xmlStrEqual(name, cur->name)))
9129 break;
9130 n++;
9131 if (n == indx)
9132 addNode(list, cur);
9133 }
9134 break;
9135 case NODE_TEST_ALL:
9136 if (axis == AXIS_ATTRIBUTE) {
9137 if (cur->type == XML_ATTRIBUTE_NODE) {
9138 n++;
9139 if (n == indx)
9140 addNode(list, cur);
9141 }
9142 } else if (axis == AXIS_NAMESPACE) {
9143 if (cur->type == XML_NAMESPACE_DECL) {
9144 n++;
9145 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009146 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9147 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009148 }
9149 } else {
9150 if (cur->type == XML_ELEMENT_NODE) {
9151 if (prefix == NULL) {
9152 n++;
9153 if (n == indx)
9154 addNode(list, cur);
9155 } else if ((cur->ns != NULL) &&
9156 (xmlStrEqual(URI, cur->ns->href))) {
9157 n++;
9158 if (n == indx)
9159 addNode(list, cur);
9160 }
9161 }
9162 }
9163 break;
9164 case NODE_TEST_NS:{
9165 TODO;
9166 break;
9167 }
9168 case NODE_TEST_NAME:
9169 switch (cur->type) {
9170 case XML_ELEMENT_NODE:
9171 if (xmlStrEqual(name, cur->name)) {
9172 if (prefix == NULL) {
9173 if (cur->ns == NULL) {
9174 n++;
9175 if (n == indx)
9176 addNode(list, cur);
9177 }
9178 } else {
9179 if ((cur->ns != NULL) &&
9180 (xmlStrEqual(URI,
9181 cur->ns->href))) {
9182 n++;
9183 if (n == indx)
9184 addNode(list, cur);
9185 }
9186 }
9187 }
9188 break;
9189 case XML_ATTRIBUTE_NODE:{
9190 xmlAttrPtr attr = (xmlAttrPtr) cur;
9191
9192 if (xmlStrEqual(name, attr->name)) {
9193 if (prefix == NULL) {
9194 if ((attr->ns == NULL) ||
9195 (attr->ns->prefix == NULL)) {
9196 n++;
9197 if (n == indx)
9198 addNode(list, cur);
9199 }
9200 } else {
9201 if ((attr->ns != NULL) &&
9202 (xmlStrEqual(URI,
9203 attr->ns->
9204 href))) {
9205 n++;
9206 if (n == indx)
9207 addNode(list, cur);
9208 }
9209 }
9210 }
9211 break;
9212 }
9213 case XML_NAMESPACE_DECL:
9214 if (cur->type == XML_NAMESPACE_DECL) {
9215 xmlNsPtr ns = (xmlNsPtr) cur;
9216
9217 if ((ns->prefix != NULL) && (name != NULL)
9218 && (xmlStrEqual(ns->prefix, name))) {
9219 n++;
9220 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009221 xmlXPathNodeSetAddNs(list,
9222 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009223 }
9224 }
9225 break;
9226 default:
9227 break;
9228 }
9229 break;
9230 break;
9231 }
9232 } while (n < indx);
9233 }
9234 ctxt->context->node = tmp;
9235#ifdef DEBUG_STEP_NTH
9236 xmlGenericError(xmlGenericErrorContext,
9237 "\nExamined %d nodes, found %d nodes at that step\n",
9238 t, list->nodeNr);
9239#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009240 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009241 if ((obj->boolval) && (obj->user != NULL)) {
9242 ctxt->value->boolval = 1;
9243 ctxt->value->user = obj->user;
9244 obj->user = NULL;
9245 obj->boolval = 0;
9246 }
9247 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009248 return(t);
9249}
9250
9251/**
9252 * xmlXPathCompOpEvalFirst:
9253 * @ctxt: the XPath parser context with the compiled expression
9254 * @op: an XPath compiled operation
9255 * @first: the first elem found so far
9256 *
9257 * Evaluate the Precompiled XPath operation searching only the first
9258 * element in document order
9259 *
9260 * Returns the number of examined objects.
9261 */
9262static int
9263xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9264 xmlXPathStepOpPtr op, xmlNodePtr * first)
9265{
9266 int total = 0, cur;
9267 xmlXPathCompExprPtr comp;
9268 xmlXPathObjectPtr arg1, arg2;
9269
Daniel Veillard556c6682001-10-06 09:59:51 +00009270 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009271 comp = ctxt->comp;
9272 switch (op->op) {
9273 case XPATH_OP_END:
9274 return (0);
9275 case XPATH_OP_UNION:
9276 total =
9277 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9278 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009279 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009280 if ((ctxt->value != NULL)
9281 && (ctxt->value->type == XPATH_NODESET)
9282 && (ctxt->value->nodesetval != NULL)
9283 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9284 /*
9285 * limit tree traversing to first node in the result
9286 */
9287 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9288 *first = ctxt->value->nodesetval->nodeTab[0];
9289 }
9290 cur =
9291 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9292 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009293 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009294 CHECK_TYPE0(XPATH_NODESET);
9295 arg2 = valuePop(ctxt);
9296
9297 CHECK_TYPE0(XPATH_NODESET);
9298 arg1 = valuePop(ctxt);
9299
9300 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9301 arg2->nodesetval);
9302 valuePush(ctxt, arg1);
9303 xmlXPathFreeObject(arg2);
9304 /* optimizer */
9305 if (total > cur)
9306 xmlXPathCompSwap(op);
9307 return (total + cur);
9308 case XPATH_OP_ROOT:
9309 xmlXPathRoot(ctxt);
9310 return (0);
9311 case XPATH_OP_NODE:
9312 if (op->ch1 != -1)
9313 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009314 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009315 if (op->ch2 != -1)
9316 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009317 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009318 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9319 return (total);
9320 case XPATH_OP_RESET:
9321 if (op->ch1 != -1)
9322 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009323 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009324 if (op->ch2 != -1)
9325 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009326 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009327 ctxt->context->node = NULL;
9328 return (total);
9329 case XPATH_OP_COLLECT:{
9330 if (op->ch1 == -1)
9331 return (total);
9332
9333 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009334 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009335
9336 /*
9337 * Optimization for [n] selection where n is a number
9338 */
9339 if ((op->ch2 != -1) &&
9340 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9341 (comp->steps[op->ch2].ch1 == -1) &&
9342 (comp->steps[op->ch2].ch2 != -1) &&
9343 (comp->steps[comp->steps[op->ch2].ch2].op ==
9344 XPATH_OP_VALUE)) {
9345 xmlXPathObjectPtr val;
9346
9347 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9348 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9349 int indx = (int) val->floatval;
9350
9351 if (val->floatval == (float) indx) {
9352 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9353 first, NULL);
9354 return (total);
9355 }
9356 }
9357 }
9358 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9359 return (total);
9360 }
9361 case XPATH_OP_VALUE:
9362 valuePush(ctxt,
9363 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9364 return (0);
9365 case XPATH_OP_SORT:
9366 if (op->ch1 != -1)
9367 total +=
9368 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9369 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009370 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009371 if ((ctxt->value != NULL)
9372 && (ctxt->value->type == XPATH_NODESET)
9373 && (ctxt->value->nodesetval != NULL))
9374 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9375 return (total);
9376 default:
9377 return (xmlXPathCompOpEval(ctxt, op));
9378 }
9379}
9380
9381/**
9382 * xmlXPathCompOpEvalLast:
9383 * @ctxt: the XPath parser context with the compiled expression
9384 * @op: an XPath compiled operation
9385 * @last: the last elem found so far
9386 *
9387 * Evaluate the Precompiled XPath operation searching only the last
9388 * element in document order
9389 *
9390 * Returns the number of node traversed
9391 */
9392static int
9393xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9394 xmlNodePtr * last)
9395{
9396 int total = 0, cur;
9397 xmlXPathCompExprPtr comp;
9398 xmlXPathObjectPtr arg1, arg2;
9399
Daniel Veillard556c6682001-10-06 09:59:51 +00009400 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009401 comp = ctxt->comp;
9402 switch (op->op) {
9403 case XPATH_OP_END:
9404 return (0);
9405 case XPATH_OP_UNION:
9406 total =
9407 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009408 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009409 if ((ctxt->value != NULL)
9410 && (ctxt->value->type == XPATH_NODESET)
9411 && (ctxt->value->nodesetval != NULL)
9412 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9413 /*
9414 * limit tree traversing to first node in the result
9415 */
9416 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9417 *last =
9418 ctxt->value->nodesetval->nodeTab[ctxt->value->
9419 nodesetval->nodeNr -
9420 1];
9421 }
9422 cur =
9423 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009424 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009425 if ((ctxt->value != NULL)
9426 && (ctxt->value->type == XPATH_NODESET)
9427 && (ctxt->value->nodesetval != NULL)
9428 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9429 }
9430 CHECK_TYPE0(XPATH_NODESET);
9431 arg2 = valuePop(ctxt);
9432
9433 CHECK_TYPE0(XPATH_NODESET);
9434 arg1 = valuePop(ctxt);
9435
9436 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9437 arg2->nodesetval);
9438 valuePush(ctxt, arg1);
9439 xmlXPathFreeObject(arg2);
9440 /* optimizer */
9441 if (total > cur)
9442 xmlXPathCompSwap(op);
9443 return (total + cur);
9444 case XPATH_OP_ROOT:
9445 xmlXPathRoot(ctxt);
9446 return (0);
9447 case XPATH_OP_NODE:
9448 if (op->ch1 != -1)
9449 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009450 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009451 if (op->ch2 != -1)
9452 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009453 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009454 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9455 return (total);
9456 case XPATH_OP_RESET:
9457 if (op->ch1 != -1)
9458 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009459 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009460 if (op->ch2 != -1)
9461 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009462 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009463 ctxt->context->node = NULL;
9464 return (total);
9465 case XPATH_OP_COLLECT:{
9466 if (op->ch1 == -1)
9467 return (0);
9468
9469 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009470 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009471
9472 /*
9473 * Optimization for [n] selection where n is a number
9474 */
9475 if ((op->ch2 != -1) &&
9476 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9477 (comp->steps[op->ch2].ch1 == -1) &&
9478 (comp->steps[op->ch2].ch2 != -1) &&
9479 (comp->steps[comp->steps[op->ch2].ch2].op ==
9480 XPATH_OP_VALUE)) {
9481 xmlXPathObjectPtr val;
9482
9483 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9484 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9485 int indx = (int) val->floatval;
9486
9487 if (val->floatval == (float) indx) {
9488 total +=
9489 xmlXPathNodeCollectAndTestNth(ctxt, op,
9490 indx, NULL,
9491 last);
9492 return (total);
9493 }
9494 }
9495 }
9496 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9497 return (total);
9498 }
9499 case XPATH_OP_VALUE:
9500 valuePush(ctxt,
9501 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9502 return (0);
9503 case XPATH_OP_SORT:
9504 if (op->ch1 != -1)
9505 total +=
9506 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9507 last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009508 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009509 if ((ctxt->value != NULL)
9510 && (ctxt->value->type == XPATH_NODESET)
9511 && (ctxt->value->nodesetval != NULL))
9512 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9513 return (total);
9514 default:
9515 return (xmlXPathCompOpEval(ctxt, op));
9516 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009517}
9518
Owen Taylor3473f882001-02-23 17:55:21 +00009519/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009520 * xmlXPathCompOpEval:
9521 * @ctxt: the XPath parser context with the compiled expression
9522 * @op: an XPath compiled operation
9523 *
9524 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009525 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009526 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009527static int
9528xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9529{
9530 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009531 int equal, ret;
9532 xmlXPathCompExprPtr comp;
9533 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009534 xmlNodePtr bak;
9535 xmlDocPtr bakd;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009536
Daniel Veillard556c6682001-10-06 09:59:51 +00009537 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009538 comp = ctxt->comp;
9539 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009540 case XPATH_OP_END:
9541 return (0);
9542 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009543 bakd = ctxt->context->doc;
9544 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009545 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009546 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009547 xmlXPathBooleanFunction(ctxt, 1);
9548 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9549 return (total);
9550 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009551 ctxt->context->doc = bakd;
9552 ctxt->context->node = bak;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009553 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009554 if (ctxt->error) {
9555 xmlXPathFreeObject(arg2);
9556 return(0);
9557 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009558 xmlXPathBooleanFunction(ctxt, 1);
9559 arg1 = valuePop(ctxt);
9560 arg1->boolval &= arg2->boolval;
9561 valuePush(ctxt, arg1);
9562 xmlXPathFreeObject(arg2);
9563 return (total);
9564 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009565 bakd = ctxt->context->doc;
9566 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009567 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009568 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009569 xmlXPathBooleanFunction(ctxt, 1);
9570 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9571 return (total);
9572 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009573 ctxt->context->doc = bakd;
9574 ctxt->context->node = bak;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009575 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009576 if (ctxt->error) {
9577 xmlXPathFreeObject(arg2);
9578 return(0);
9579 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009580 xmlXPathBooleanFunction(ctxt, 1);
9581 arg1 = valuePop(ctxt);
9582 arg1->boolval |= arg2->boolval;
9583 valuePush(ctxt, arg1);
9584 xmlXPathFreeObject(arg2);
9585 return (total);
9586 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009587 bakd = ctxt->context->doc;
9588 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009589 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009590 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009591 ctxt->context->doc = bakd;
9592 ctxt->context->node = bak;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009593 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009594 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009595 equal = xmlXPathEqualValues(ctxt);
9596 if (op->value)
9597 valuePush(ctxt, xmlXPathNewBoolean(equal));
9598 else
9599 valuePush(ctxt, xmlXPathNewBoolean(!equal));
9600 return (total);
9601 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009602 bakd = ctxt->context->doc;
9603 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009604 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009605 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009606 ctxt->context->doc = bakd;
9607 ctxt->context->node = bak;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009608 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009609 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009610 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
9611 valuePush(ctxt, xmlXPathNewBoolean(ret));
9612 return (total);
9613 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009614 bakd = ctxt->context->doc;
9615 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009616 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009617 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009618 if (op->ch2 != -1) {
9619 ctxt->context->doc = bakd;
9620 ctxt->context->node = bak;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009621 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009622 }
Daniel Veillard556c6682001-10-06 09:59:51 +00009623 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009624 if (op->value == 0)
9625 xmlXPathSubValues(ctxt);
9626 else if (op->value == 1)
9627 xmlXPathAddValues(ctxt);
9628 else if (op->value == 2)
9629 xmlXPathValueFlipSign(ctxt);
9630 else if (op->value == 3) {
9631 CAST_TO_NUMBER;
9632 CHECK_TYPE0(XPATH_NUMBER);
9633 }
9634 return (total);
9635 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009636 bakd = ctxt->context->doc;
9637 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009638 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009639 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009640 ctxt->context->doc = bakd;
9641 ctxt->context->node = bak;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009642 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009643 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009644 if (op->value == 0)
9645 xmlXPathMultValues(ctxt);
9646 else if (op->value == 1)
9647 xmlXPathDivValues(ctxt);
9648 else if (op->value == 2)
9649 xmlXPathModValues(ctxt);
9650 return (total);
9651 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009652 bakd = ctxt->context->doc;
9653 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009654 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009655 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009656 ctxt->context->doc = bakd;
9657 ctxt->context->node = bak;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009658 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009659 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009660 CHECK_TYPE0(XPATH_NODESET);
9661 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009662
Daniel Veillardf06307e2001-07-03 10:35:50 +00009663 CHECK_TYPE0(XPATH_NODESET);
9664 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009665
Daniel Veillardf06307e2001-07-03 10:35:50 +00009666 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9667 arg2->nodesetval);
9668 valuePush(ctxt, arg1);
9669 xmlXPathFreeObject(arg2);
9670 return (total);
9671 case XPATH_OP_ROOT:
9672 xmlXPathRoot(ctxt);
9673 return (total);
9674 case XPATH_OP_NODE:
9675 if (op->ch1 != -1)
9676 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009677 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009678 if (op->ch2 != -1)
9679 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009680 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009681 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9682 return (total);
9683 case XPATH_OP_RESET:
9684 if (op->ch1 != -1)
9685 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009686 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009687 if (op->ch2 != -1)
9688 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009689 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009690 ctxt->context->node = NULL;
9691 return (total);
9692 case XPATH_OP_COLLECT:{
9693 if (op->ch1 == -1)
9694 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009695
Daniel Veillardf06307e2001-07-03 10:35:50 +00009696 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009697 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009698
Daniel Veillardf06307e2001-07-03 10:35:50 +00009699 /*
9700 * Optimization for [n] selection where n is a number
9701 */
9702 if ((op->ch2 != -1) &&
9703 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9704 (comp->steps[op->ch2].ch1 == -1) &&
9705 (comp->steps[op->ch2].ch2 != -1) &&
9706 (comp->steps[comp->steps[op->ch2].ch2].op ==
9707 XPATH_OP_VALUE)) {
9708 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +00009709
Daniel Veillardf06307e2001-07-03 10:35:50 +00009710 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9711 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9712 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009713
Daniel Veillardf06307e2001-07-03 10:35:50 +00009714 if (val->floatval == (float) indx) {
9715 total +=
9716 xmlXPathNodeCollectAndTestNth(ctxt, op,
9717 indx, NULL,
9718 NULL);
9719 return (total);
9720 }
9721 }
9722 }
9723 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
9724 return (total);
9725 }
9726 case XPATH_OP_VALUE:
9727 valuePush(ctxt,
9728 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9729 return (total);
9730 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +00009731 xmlXPathObjectPtr val;
9732
Daniel Veillardf06307e2001-07-03 10:35:50 +00009733 if (op->ch1 != -1)
9734 total +=
9735 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009736 if (op->value5 == NULL) {
9737 val = xmlXPathVariableLookup(ctxt->context, op->value4);
9738 if (val == NULL) {
9739 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
9740 return(0);
9741 }
9742 valuePush(ctxt, val);
9743 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009744 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009745
Daniel Veillardf06307e2001-07-03 10:35:50 +00009746 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9747 if (URI == NULL) {
9748 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009749 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009750 op->value4, op->value5);
9751 return (total);
9752 }
Daniel Veillard556c6682001-10-06 09:59:51 +00009753 val = xmlXPathVariableLookupNS(ctxt->context,
9754 op->value4, URI);
9755 if (val == NULL) {
9756 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
9757 return(0);
9758 }
9759 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009760 }
9761 return (total);
9762 }
9763 case XPATH_OP_FUNCTION:{
9764 xmlXPathFunction func;
9765 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +00009766 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009767
9768 if (op->ch1 != -1)
9769 total +=
9770 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009771 if (ctxt->valueNr < op->value) {
9772 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009773 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +00009774 ctxt->error = XPATH_INVALID_OPERAND;
9775 return (total);
9776 }
9777 for (i = 0; i < op->value; i++)
9778 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
9779 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009780 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +00009781 ctxt->error = XPATH_INVALID_OPERAND;
9782 return (total);
9783 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009784 if (op->cache != NULL)
9785 func = (xmlXPathFunction) op->cache;
9786 else {
9787 const xmlChar *URI = NULL;
9788
9789 if (op->value5 == NULL)
9790 func =
9791 xmlXPathFunctionLookup(ctxt->context,
9792 op->value4);
9793 else {
9794 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9795 if (URI == NULL) {
9796 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009797 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009798 op->value4, op->value5);
9799 return (total);
9800 }
9801 func = xmlXPathFunctionLookupNS(ctxt->context,
9802 op->value4, URI);
9803 }
9804 if (func == NULL) {
9805 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009806 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009807 op->value4);
9808 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009809 }
9810 op->cache = (void *) func;
9811 op->cacheURI = (void *) URI;
9812 }
9813 oldFunc = ctxt->context->function;
9814 oldFuncURI = ctxt->context->functionURI;
9815 ctxt->context->function = op->value4;
9816 ctxt->context->functionURI = op->cacheURI;
9817 func(ctxt, op->value);
9818 ctxt->context->function = oldFunc;
9819 ctxt->context->functionURI = oldFuncURI;
9820 return (total);
9821 }
9822 case XPATH_OP_ARG:
9823 if (op->ch1 != -1)
9824 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009825 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009826 if (op->ch2 != -1)
9827 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009828 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009829 return (total);
9830 case XPATH_OP_PREDICATE:
9831 case XPATH_OP_FILTER:{
9832 xmlXPathObjectPtr res;
9833 xmlXPathObjectPtr obj, tmp;
9834 xmlNodeSetPtr newset = NULL;
9835 xmlNodeSetPtr oldset;
9836 xmlNodePtr oldnode;
9837 int i;
9838
9839 /*
9840 * Optimization for ()[1] selection i.e. the first elem
9841 */
9842 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9843 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9844 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
9845 xmlXPathObjectPtr val;
9846
9847 val = comp->steps[op->ch2].value4;
9848 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
9849 (val->floatval == 1.0)) {
9850 xmlNodePtr first = NULL;
9851
9852 total +=
9853 xmlXPathCompOpEvalFirst(ctxt,
9854 &comp->steps[op->ch1],
9855 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009856 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009857 /*
9858 * The nodeset should be in document order,
9859 * Keep only the first value
9860 */
9861 if ((ctxt->value != NULL) &&
9862 (ctxt->value->type == XPATH_NODESET) &&
9863 (ctxt->value->nodesetval != NULL) &&
9864 (ctxt->value->nodesetval->nodeNr > 1))
9865 ctxt->value->nodesetval->nodeNr = 1;
9866 return (total);
9867 }
9868 }
9869 /*
9870 * Optimization for ()[last()] selection i.e. the last elem
9871 */
9872 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9873 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9874 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
9875 int f = comp->steps[op->ch2].ch1;
9876
9877 if ((f != -1) &&
9878 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
9879 (comp->steps[f].value5 == NULL) &&
9880 (comp->steps[f].value == 0) &&
9881 (comp->steps[f].value4 != NULL) &&
9882 (xmlStrEqual
9883 (comp->steps[f].value4, BAD_CAST "last"))) {
9884 xmlNodePtr last = NULL;
9885
9886 total +=
9887 xmlXPathCompOpEvalLast(ctxt,
9888 &comp->steps[op->ch1],
9889 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009890 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009891 /*
9892 * The nodeset should be in document order,
9893 * Keep only the last value
9894 */
9895 if ((ctxt->value != NULL) &&
9896 (ctxt->value->type == XPATH_NODESET) &&
9897 (ctxt->value->nodesetval != NULL) &&
9898 (ctxt->value->nodesetval->nodeTab != NULL) &&
9899 (ctxt->value->nodesetval->nodeNr > 1)) {
9900 ctxt->value->nodesetval->nodeTab[0] =
9901 ctxt->value->nodesetval->nodeTab[ctxt->
9902 value->
9903 nodesetval->
9904 nodeNr -
9905 1];
9906 ctxt->value->nodesetval->nodeNr = 1;
9907 }
9908 return (total);
9909 }
9910 }
9911
9912 if (op->ch1 != -1)
9913 total +=
9914 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009915 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009916 if (op->ch2 == -1)
9917 return (total);
9918 if (ctxt->value == NULL)
9919 return (total);
9920
9921 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009922
9923#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00009924 /*
9925 * Hum are we filtering the result of an XPointer expression
9926 */
9927 if (ctxt->value->type == XPATH_LOCATIONSET) {
9928 xmlLocationSetPtr newlocset = NULL;
9929 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009930
Daniel Veillardf06307e2001-07-03 10:35:50 +00009931 /*
9932 * Extract the old locset, and then evaluate the result of the
9933 * expression for all the element in the locset. use it to grow
9934 * up a new locset.
9935 */
9936 CHECK_TYPE0(XPATH_LOCATIONSET);
9937 obj = valuePop(ctxt);
9938 oldlocset = obj->user;
9939 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009940
Daniel Veillardf06307e2001-07-03 10:35:50 +00009941 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
9942 ctxt->context->contextSize = 0;
9943 ctxt->context->proximityPosition = 0;
9944 if (op->ch2 != -1)
9945 total +=
9946 xmlXPathCompOpEval(ctxt,
9947 &comp->steps[op->ch2]);
9948 res = valuePop(ctxt);
9949 if (res != NULL)
9950 xmlXPathFreeObject(res);
9951 valuePush(ctxt, obj);
9952 CHECK_ERROR0;
9953 return (total);
9954 }
9955 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009956
Daniel Veillardf06307e2001-07-03 10:35:50 +00009957 for (i = 0; i < oldlocset->locNr; i++) {
9958 /*
9959 * Run the evaluation with a node list made of a
9960 * single item in the nodelocset.
9961 */
9962 ctxt->context->node = oldlocset->locTab[i]->user;
9963 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9964 valuePush(ctxt, tmp);
9965 ctxt->context->contextSize = oldlocset->locNr;
9966 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009967
Daniel Veillardf06307e2001-07-03 10:35:50 +00009968 if (op->ch2 != -1)
9969 total +=
9970 xmlXPathCompOpEval(ctxt,
9971 &comp->steps[op->ch2]);
9972 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009973
Daniel Veillardf06307e2001-07-03 10:35:50 +00009974 /*
9975 * The result of the evaluation need to be tested to
9976 * decided whether the filter succeeded or not
9977 */
9978 res = valuePop(ctxt);
9979 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
9980 xmlXPtrLocationSetAdd(newlocset,
9981 xmlXPathObjectCopy
9982 (oldlocset->locTab[i]));
9983 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009984
Daniel Veillardf06307e2001-07-03 10:35:50 +00009985 /*
9986 * Cleanup
9987 */
9988 if (res != NULL)
9989 xmlXPathFreeObject(res);
9990 if (ctxt->value == tmp) {
9991 res = valuePop(ctxt);
9992 xmlXPathFreeObject(res);
9993 }
9994
9995 ctxt->context->node = NULL;
9996 }
9997
9998 /*
9999 * The result is used as the new evaluation locset.
10000 */
10001 xmlXPathFreeObject(obj);
10002 ctxt->context->node = NULL;
10003 ctxt->context->contextSize = -1;
10004 ctxt->context->proximityPosition = -1;
10005 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10006 ctxt->context->node = oldnode;
10007 return (total);
10008 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010009#endif /* LIBXML_XPTR_ENABLED */
10010
Daniel Veillardf06307e2001-07-03 10:35:50 +000010011 /*
10012 * Extract the old set, and then evaluate the result of the
10013 * expression for all the element in the set. use it to grow
10014 * up a new set.
10015 */
10016 CHECK_TYPE0(XPATH_NODESET);
10017 obj = valuePop(ctxt);
10018 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010019
Daniel Veillardf06307e2001-07-03 10:35:50 +000010020 oldnode = ctxt->context->node;
10021 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010022
Daniel Veillardf06307e2001-07-03 10:35:50 +000010023 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10024 ctxt->context->contextSize = 0;
10025 ctxt->context->proximityPosition = 0;
10026 if (op->ch2 != -1)
10027 total +=
10028 xmlXPathCompOpEval(ctxt,
10029 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010030 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010031 res = valuePop(ctxt);
10032 if (res != NULL)
10033 xmlXPathFreeObject(res);
10034 valuePush(ctxt, obj);
10035 ctxt->context->node = oldnode;
10036 CHECK_ERROR0;
10037 } else {
10038 /*
10039 * Initialize the new set.
10040 */
10041 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010042
Daniel Veillardf06307e2001-07-03 10:35:50 +000010043 for (i = 0; i < oldset->nodeNr; i++) {
10044 /*
10045 * Run the evaluation with a node list made of
10046 * a single item in the nodeset.
10047 */
10048 ctxt->context->node = oldset->nodeTab[i];
10049 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10050 valuePush(ctxt, tmp);
10051 ctxt->context->contextSize = oldset->nodeNr;
10052 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010053
Daniel Veillardf06307e2001-07-03 10:35:50 +000010054 if (op->ch2 != -1)
10055 total +=
10056 xmlXPathCompOpEval(ctxt,
10057 &comp->steps[op->ch2]);
10058 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010059
Daniel Veillardf06307e2001-07-03 10:35:50 +000010060 /*
10061 * The result of the evaluation need to be tested to
10062 * decided whether the filter succeeded or not
10063 */
10064 res = valuePop(ctxt);
10065 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10066 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10067 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010068
Daniel Veillardf06307e2001-07-03 10:35:50 +000010069 /*
10070 * Cleanup
10071 */
10072 if (res != NULL)
10073 xmlXPathFreeObject(res);
10074 if (ctxt->value == tmp) {
10075 res = valuePop(ctxt);
10076 xmlXPathFreeObject(res);
10077 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010078
Daniel Veillardf06307e2001-07-03 10:35:50 +000010079 ctxt->context->node = NULL;
10080 }
10081
10082 /*
10083 * The result is used as the new evaluation set.
10084 */
10085 xmlXPathFreeObject(obj);
10086 ctxt->context->node = NULL;
10087 ctxt->context->contextSize = -1;
10088 ctxt->context->proximityPosition = -1;
10089 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10090 }
10091 ctxt->context->node = oldnode;
10092 return (total);
10093 }
10094 case XPATH_OP_SORT:
10095 if (op->ch1 != -1)
10096 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010097 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010098 if ((ctxt->value != NULL) &&
10099 (ctxt->value->type == XPATH_NODESET) &&
10100 (ctxt->value->nodesetval != NULL))
10101 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10102 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010103#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010104 case XPATH_OP_RANGETO:{
10105 xmlXPathObjectPtr range;
10106 xmlXPathObjectPtr res, obj;
10107 xmlXPathObjectPtr tmp;
10108 xmlLocationSetPtr newset = NULL;
10109 xmlNodeSetPtr oldset;
10110 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010111
Daniel Veillardf06307e2001-07-03 10:35:50 +000010112 if (op->ch1 != -1)
10113 total +=
10114 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10115 if (op->ch2 == -1)
10116 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010117
Daniel Veillardf06307e2001-07-03 10:35:50 +000010118 CHECK_TYPE0(XPATH_NODESET);
10119 obj = valuePop(ctxt);
10120 oldset = obj->nodesetval;
10121 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010122
Daniel Veillardf06307e2001-07-03 10:35:50 +000010123 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010124
Daniel Veillardf06307e2001-07-03 10:35:50 +000010125 if (oldset != NULL) {
10126 for (i = 0; i < oldset->nodeNr; i++) {
10127 /*
10128 * Run the evaluation with a node list made of a single item
10129 * in the nodeset.
10130 */
10131 ctxt->context->node = oldset->nodeTab[i];
10132 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10133 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010134
Daniel Veillardf06307e2001-07-03 10:35:50 +000010135 if (op->ch2 != -1)
10136 total +=
10137 xmlXPathCompOpEval(ctxt,
10138 &comp->steps[op->ch2]);
10139 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010140
Daniel Veillardf06307e2001-07-03 10:35:50 +000010141 /*
10142 * The result of the evaluation need to be tested to
10143 * decided whether the filter succeeded or not
10144 */
10145 res = valuePop(ctxt);
10146 range =
10147 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10148 res);
10149 if (range != NULL) {
10150 xmlXPtrLocationSetAdd(newset, range);
10151 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010152
Daniel Veillardf06307e2001-07-03 10:35:50 +000010153 /*
10154 * Cleanup
10155 */
10156 if (res != NULL)
10157 xmlXPathFreeObject(res);
10158 if (ctxt->value == tmp) {
10159 res = valuePop(ctxt);
10160 xmlXPathFreeObject(res);
10161 }
10162
10163 ctxt->context->node = NULL;
10164 }
10165 }
10166
10167 /*
10168 * The result is used as the new evaluation set.
10169 */
10170 xmlXPathFreeObject(obj);
10171 ctxt->context->node = NULL;
10172 ctxt->context->contextSize = -1;
10173 ctxt->context->proximityPosition = -1;
10174 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
10175 return (total);
10176 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010177#endif /* LIBXML_XPTR_ENABLED */
10178 }
10179 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010180 "XPath: unknown precompiled operation %d\n", op->op);
10181 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010182}
10183
10184/**
10185 * xmlXPathRunEval:
10186 * @ctxt: the XPath parser context with the compiled expression
10187 *
10188 * Evaluate the Precompiled XPath expression in the given context.
10189 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010190static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010191xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10192 xmlXPathCompExprPtr comp;
10193
10194 if ((ctxt == NULL) || (ctxt->comp == NULL))
10195 return;
10196
10197 if (ctxt->valueTab == NULL) {
10198 /* Allocate the value stack */
10199 ctxt->valueTab = (xmlXPathObjectPtr *)
10200 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10201 if (ctxt->valueTab == NULL) {
10202 xmlFree(ctxt);
10203 xmlGenericError(xmlGenericErrorContext,
10204 "xmlXPathRunEval: out of memory\n");
10205 return;
10206 }
10207 ctxt->valueNr = 0;
10208 ctxt->valueMax = 10;
10209 ctxt->value = NULL;
10210 }
10211 comp = ctxt->comp;
10212 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10213}
10214
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010215/************************************************************************
10216 * *
10217 * Public interfaces *
10218 * *
10219 ************************************************************************/
10220
10221/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010222 * xmlXPathEvalPredicate:
10223 * @ctxt: the XPath context
10224 * @res: the Predicate Expression evaluation result
10225 *
10226 * Evaluate a predicate result for the current node.
10227 * A PredicateExpr is evaluated by evaluating the Expr and converting
10228 * the result to a boolean. If the result is a number, the result will
10229 * be converted to true if the number is equal to the position of the
10230 * context node in the context node list (as returned by the position
10231 * function) and will be converted to false otherwise; if the result
10232 * is not a number, then the result will be converted as if by a call
10233 * to the boolean function.
10234 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010235 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010236 */
10237int
10238xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
10239 if (res == NULL) return(0);
10240 switch (res->type) {
10241 case XPATH_BOOLEAN:
10242 return(res->boolval);
10243 case XPATH_NUMBER:
10244 return(res->floatval == ctxt->proximityPosition);
10245 case XPATH_NODESET:
10246 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010247 if (res->nodesetval == NULL)
10248 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010249 return(res->nodesetval->nodeNr != 0);
10250 case XPATH_STRING:
10251 return((res->stringval != NULL) &&
10252 (xmlStrlen(res->stringval) != 0));
10253 default:
10254 STRANGE
10255 }
10256 return(0);
10257}
10258
10259/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010260 * xmlXPathEvaluatePredicateResult:
10261 * @ctxt: the XPath Parser context
10262 * @res: the Predicate Expression evaluation result
10263 *
10264 * Evaluate a predicate result for the current node.
10265 * A PredicateExpr is evaluated by evaluating the Expr and converting
10266 * the result to a boolean. If the result is a number, the result will
10267 * be converted to true if the number is equal to the position of the
10268 * context node in the context node list (as returned by the position
10269 * function) and will be converted to false otherwise; if the result
10270 * is not a number, then the result will be converted as if by a call
10271 * to the boolean function.
10272 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010273 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010274 */
10275int
10276xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10277 xmlXPathObjectPtr res) {
10278 if (res == NULL) return(0);
10279 switch (res->type) {
10280 case XPATH_BOOLEAN:
10281 return(res->boolval);
10282 case XPATH_NUMBER:
10283 return(res->floatval == ctxt->context->proximityPosition);
10284 case XPATH_NODESET:
10285 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000010286 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000010287 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010288 return(res->nodesetval->nodeNr != 0);
10289 case XPATH_STRING:
10290 return((res->stringval != NULL) &&
10291 (xmlStrlen(res->stringval) != 0));
10292 default:
10293 STRANGE
10294 }
10295 return(0);
10296}
10297
10298/**
10299 * xmlXPathCompile:
10300 * @str: the XPath expression
10301 *
10302 * Compile an XPath expression
10303 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010304 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010305 * the caller has to free the object.
10306 */
10307xmlXPathCompExprPtr
10308xmlXPathCompile(const xmlChar *str) {
10309 xmlXPathParserContextPtr ctxt;
10310 xmlXPathCompExprPtr comp;
10311
10312 xmlXPathInit();
10313
10314 ctxt = xmlXPathNewParserContext(str, NULL);
10315 xmlXPathCompileExpr(ctxt);
10316
Daniel Veillard40af6492001-04-22 08:50:55 +000010317 if (*ctxt->cur != 0) {
10318 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10319 comp = NULL;
10320 } else {
10321 comp = ctxt->comp;
10322 ctxt->comp = NULL;
10323 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010324 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010325#ifdef DEBUG_EVAL_COUNTS
10326 if (comp != NULL) {
10327 comp->string = xmlStrdup(str);
10328 comp->nb = 0;
10329 }
10330#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010331 return(comp);
10332}
10333
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010334/**
10335 * xmlXPathCompiledEval:
10336 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000010337 * @ctx: the XPath context
10338 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010339 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000010340 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010341 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000010342 * the caller has to free the object.
10343 */
10344xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010345xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000010346 xmlXPathParserContextPtr ctxt;
10347 xmlXPathObjectPtr res, tmp, init = NULL;
10348 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000010349#ifndef LIBXML_THREAD_ENABLED
10350 static int reentance = 0;
10351#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010352
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010353 if ((comp == NULL) || (ctx == NULL))
10354 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010355 xmlXPathInit();
10356
10357 CHECK_CONTEXT(ctx)
10358
Daniel Veillard81463942001-10-16 12:34:39 +000010359#ifndef LIBXML_THREAD_ENABLED
10360 reentance++;
10361 if (reentance > 1)
10362 xmlXPathDisableOptimizer = 1;
10363#endif
10364
Daniel Veillardf06307e2001-07-03 10:35:50 +000010365#ifdef DEBUG_EVAL_COUNTS
10366 comp->nb++;
10367 if ((comp->string != NULL) && (comp->nb > 100)) {
10368 fprintf(stderr, "100 x %s\n", comp->string);
10369 comp->nb = 0;
10370 }
10371#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010372 ctxt = xmlXPathCompParserContext(comp, ctx);
10373 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010374
10375 if (ctxt->value == NULL) {
10376 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010377 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000010378 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000010379 } else {
10380 res = valuePop(ctxt);
10381 }
10382
Daniel Veillardf06307e2001-07-03 10:35:50 +000010383
Owen Taylor3473f882001-02-23 17:55:21 +000010384 do {
10385 tmp = valuePop(ctxt);
10386 if (tmp != NULL) {
10387 if (tmp != init)
10388 stack++;
10389 xmlXPathFreeObject(tmp);
10390 }
10391 } while (tmp != NULL);
10392 if ((stack != 0) && (res != NULL)) {
10393 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010394 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000010395 stack);
10396 }
10397 if (ctxt->error != XPATH_EXPRESSION_OK) {
10398 xmlXPathFreeObject(res);
10399 res = NULL;
10400 }
10401
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010402
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010403 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010404 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000010405#ifndef LIBXML_THREAD_ENABLED
10406 reentance--;
10407#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010408 return(res);
10409}
10410
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010411/**
10412 * xmlXPathEvalExpr:
10413 * @ctxt: the XPath Parser context
10414 *
10415 * Parse and evaluate an XPath expression in the given context,
10416 * then push the result on the context stack
10417 */
10418void
10419xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
10420 xmlXPathCompileExpr(ctxt);
10421 xmlXPathRunEval(ctxt);
10422}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010423
10424/**
10425 * xmlXPathEval:
10426 * @str: the XPath expression
10427 * @ctx: the XPath context
10428 *
10429 * Evaluate the XPath Location Path in the given context.
10430 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010431 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010432 * the caller has to free the object.
10433 */
10434xmlXPathObjectPtr
10435xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
10436 xmlXPathParserContextPtr ctxt;
10437 xmlXPathObjectPtr res, tmp, init = NULL;
10438 int stack = 0;
10439
10440 xmlXPathInit();
10441
10442 CHECK_CONTEXT(ctx)
10443
10444 ctxt = xmlXPathNewParserContext(str, ctx);
10445 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010446
10447 if (ctxt->value == NULL) {
10448 xmlGenericError(xmlGenericErrorContext,
10449 "xmlXPathEval: evaluation failed\n");
10450 res = NULL;
10451 } else if (*ctxt->cur != 0) {
10452 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10453 res = NULL;
10454 } else {
10455 res = valuePop(ctxt);
10456 }
10457
10458 do {
10459 tmp = valuePop(ctxt);
10460 if (tmp != NULL) {
10461 if (tmp != init)
10462 stack++;
10463 xmlXPathFreeObject(tmp);
10464 }
10465 } while (tmp != NULL);
10466 if ((stack != 0) && (res != NULL)) {
10467 xmlGenericError(xmlGenericErrorContext,
10468 "xmlXPathEval: %d object left on the stack\n",
10469 stack);
10470 }
10471 if (ctxt->error != XPATH_EXPRESSION_OK) {
10472 xmlXPathFreeObject(res);
10473 res = NULL;
10474 }
10475
Owen Taylor3473f882001-02-23 17:55:21 +000010476 xmlXPathFreeParserContext(ctxt);
10477 return(res);
10478}
10479
10480/**
10481 * xmlXPathEvalExpression:
10482 * @str: the XPath expression
10483 * @ctxt: the XPath context
10484 *
10485 * Evaluate the XPath expression in the given context.
10486 *
10487 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
10488 * the caller has to free the object.
10489 */
10490xmlXPathObjectPtr
10491xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
10492 xmlXPathParserContextPtr pctxt;
10493 xmlXPathObjectPtr res, tmp;
10494 int stack = 0;
10495
10496 xmlXPathInit();
10497
10498 CHECK_CONTEXT(ctxt)
10499
10500 pctxt = xmlXPathNewParserContext(str, ctxt);
10501 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010502
10503 if (*pctxt->cur != 0) {
10504 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10505 res = NULL;
10506 } else {
10507 res = valuePop(pctxt);
10508 }
10509 do {
10510 tmp = valuePop(pctxt);
10511 if (tmp != NULL) {
10512 xmlXPathFreeObject(tmp);
10513 stack++;
10514 }
10515 } while (tmp != NULL);
10516 if ((stack != 0) && (res != NULL)) {
10517 xmlGenericError(xmlGenericErrorContext,
10518 "xmlXPathEvalExpression: %d object left on the stack\n",
10519 stack);
10520 }
10521 xmlXPathFreeParserContext(pctxt);
10522 return(res);
10523}
10524
10525/**
10526 * xmlXPathRegisterAllFunctions:
10527 * @ctxt: the XPath context
10528 *
10529 * Registers all default XPath functions in this context
10530 */
10531void
10532xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
10533{
10534 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
10535 xmlXPathBooleanFunction);
10536 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
10537 xmlXPathCeilingFunction);
10538 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
10539 xmlXPathCountFunction);
10540 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
10541 xmlXPathConcatFunction);
10542 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
10543 xmlXPathContainsFunction);
10544 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
10545 xmlXPathIdFunction);
10546 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
10547 xmlXPathFalseFunction);
10548 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
10549 xmlXPathFloorFunction);
10550 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
10551 xmlXPathLastFunction);
10552 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
10553 xmlXPathLangFunction);
10554 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
10555 xmlXPathLocalNameFunction);
10556 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
10557 xmlXPathNotFunction);
10558 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
10559 xmlXPathNameFunction);
10560 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
10561 xmlXPathNamespaceURIFunction);
10562 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
10563 xmlXPathNormalizeFunction);
10564 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
10565 xmlXPathNumberFunction);
10566 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
10567 xmlXPathPositionFunction);
10568 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
10569 xmlXPathRoundFunction);
10570 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
10571 xmlXPathStringFunction);
10572 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
10573 xmlXPathStringLengthFunction);
10574 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
10575 xmlXPathStartsWithFunction);
10576 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
10577 xmlXPathSubstringFunction);
10578 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
10579 xmlXPathSubstringBeforeFunction);
10580 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
10581 xmlXPathSubstringAfterFunction);
10582 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
10583 xmlXPathSumFunction);
10584 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
10585 xmlXPathTrueFunction);
10586 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
10587 xmlXPathTranslateFunction);
10588}
10589
10590#endif /* LIBXML_XPATH_ENABLED */