blob: dc303fcfd97fbd3cfc4913fc74709b763a807d16 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * xpath.c: XML Path Language implementation
3 * XPath is a language for addressing parts of an XML document,
4 * designed to be used by both XSLT and XPointer
5 *
6 * Reference: W3C Recommendation 16 November 1999
7 * http://www.w3.org/TR/1999/REC-xpath-19991116
8 * Public reference:
9 * http://www.w3.org/TR/xpath
10 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011 * See Copyright for the status of this software
Owen Taylor3473f882001-02-23 17:55:21 +000012 *
Daniel Veillardc5d64342001-06-24 12:13:24 +000013 * Author: daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000014 *
15 * 14 Nov 2000 ht - truncated declaration of xmlXPathEvalRelativeLocationPath
16 * for VMS
17 */
18
Daniel Veillard34ce8be2002-03-18 19:37:11 +000019#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000020#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000021#ifdef LIBXML_XPATH_ENABLED
22
Owen Taylor3473f882001-02-23 17:55:21 +000023#include <string.h>
24
25#ifdef HAVE_SYS_TYPES_H
26#include <sys/types.h>
27#endif
28#ifdef HAVE_MATH_H
29#include <math.h>
30#endif
31#ifdef HAVE_FLOAT_H
32#include <float.h>
33#endif
Owen Taylor3473f882001-02-23 17:55:21 +000034#ifdef HAVE_CTYPE_H
35#include <ctype.h>
36#endif
Daniel Veillard5792e162001-04-30 17:44:45 +000037#ifdef HAVE_SIGNAL_H
Daniel Veillardb45c43b2001-04-28 17:02:11 +000038#include <signal.h>
Daniel Veillardb45c43b2001-04-28 17:02:11 +000039#endif
Owen Taylor3473f882001-02-23 17:55:21 +000040
41#include <libxml/xmlmemory.h>
42#include <libxml/tree.h>
43#include <libxml/valid.h>
44#include <libxml/xpath.h>
45#include <libxml/xpathInternals.h>
46#include <libxml/parserInternals.h>
47#include <libxml/hash.h>
48#ifdef LIBXML_XPTR_ENABLED
49#include <libxml/xpointer.h>
50#endif
51#ifdef LIBXML_DEBUG_ENABLED
52#include <libxml/debugXML.h>
53#endif
54#include <libxml/xmlerror.h>
Daniel Veillard81463942001-10-16 12:34:39 +000055#include <libxml/threads.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000056#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000057
58/* #define DEBUG */
59/* #define DEBUG_STEP */
Daniel Veillardf06307e2001-07-03 10:35:50 +000060/* #define DEBUG_STEP_NTH */
Owen Taylor3473f882001-02-23 17:55:21 +000061/* #define DEBUG_EXPR */
Daniel Veillardf06307e2001-07-03 10:35:50 +000062/* #define DEBUG_EVAL_COUNTS */
Owen Taylor3473f882001-02-23 17:55:21 +000063
Daniel Veillard5792e162001-04-30 17:44:45 +000064double xmlXPathDivideBy(double f, double fzero);
Owen Taylor3473f882001-02-23 17:55:21 +000065
Daniel Veillard20ee8c02001-10-05 09:18:14 +000066static xmlNs xmlXPathXMLNamespaceStruct = {
67 NULL,
68 XML_NAMESPACE_DECL,
69 XML_XML_NAMESPACE,
70 BAD_CAST "xml"
71};
72static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
Daniel Veillardda423da2002-04-10 19:25:38 +000073#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +000074/*
75 * Optimizer is disabled only when threaded apps are detected while
76 * the library ain't compiled for thread safety.
77 */
78static int xmlXPathDisableOptimizer = 0;
79#endif
Daniel Veillard20ee8c02001-10-05 09:18:14 +000080
Daniel Veillard9e7160d2001-03-18 23:17:47 +000081/************************************************************************
82 * *
83 * Floating point stuff *
84 * *
85 ************************************************************************/
86
Daniel Veillardc0631a62001-09-20 13:56:06 +000087#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +000088#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +000089#endif
Daniel Veillardcda96922001-08-21 10:56:31 +000090#include "trionan.c"
91
Owen Taylor3473f882001-02-23 17:55:21 +000092/*
Owen Taylor3473f882001-02-23 17:55:21 +000093 * The lack of portability of this section of the libc is annoying !
94 */
95double xmlXPathNAN = 0;
96double xmlXPathPINF = 1;
97double xmlXPathNINF = -1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +000098double xmlXPathNZERO = 0;
Daniel Veillard20ee8c02001-10-05 09:18:14 +000099static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000100
Owen Taylor3473f882001-02-23 17:55:21 +0000101/**
102 * xmlXPathInit:
103 *
104 * Initialize the XPath environment
105 */
106void
107xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000108 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +0000109
Bjorn Reese45029602001-08-21 09:23:53 +0000110 xmlXPathPINF = trio_pinf();
111 xmlXPathNINF = trio_ninf();
112 xmlXPathNAN = trio_nan();
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000113 xmlXPathNZERO = trio_nzero();
Owen Taylor3473f882001-02-23 17:55:21 +0000114
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000115 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000116}
117
Daniel Veillardcda96922001-08-21 10:56:31 +0000118/**
119 * xmlXPathIsNaN:
120 * @val: a double value
121 *
122 * Provides a portable isnan() function to detect whether a double
123 * is a NotaNumber. Based on trio code
124 * http://sourceforge.net/projects/ctrio/
125 *
126 * Returns 1 if the value is a NaN, 0 otherwise
127 */
128int
129xmlXPathIsNaN(double val) {
130 return(trio_isnan(val));
131}
132
133/**
134 * xmlXPathIsInf:
135 * @val: a double value
136 *
137 * Provides a portable isinf() function to detect whether a double
138 * is a +Infinite or -Infinite. Based on trio code
139 * http://sourceforge.net/projects/ctrio/
140 *
141 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
142 */
143int
144xmlXPathIsInf(double val) {
145 return(trio_isinf(val));
146}
147
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000148/**
149 * xmlXPathGetSign:
150 * @val: a double value
151 *
152 * Provides a portable function to detect the sign of a double
153 * Modified from trio code
154 * http://sourceforge.net/projects/ctrio/
155 *
156 * Returns 1 if the value is Negative, 0 if positive
157 */
Daniel Veillard21458c82002-03-27 16:12:22 +0000158static int
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000159xmlXPathGetSign(double val) {
Daniel Veillard21458c82002-03-27 16:12:22 +0000160 return(trio_signbit(val));
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000161}
162
163
Owen Taylor3473f882001-02-23 17:55:21 +0000164/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000165 * *
166 * Parser Types *
167 * *
168 ************************************************************************/
169
170/*
171 * Types are private:
172 */
173
174typedef enum {
175 XPATH_OP_END=0,
176 XPATH_OP_AND,
177 XPATH_OP_OR,
178 XPATH_OP_EQUAL,
179 XPATH_OP_CMP,
180 XPATH_OP_PLUS,
181 XPATH_OP_MULT,
182 XPATH_OP_UNION,
183 XPATH_OP_ROOT,
184 XPATH_OP_NODE,
185 XPATH_OP_RESET,
186 XPATH_OP_COLLECT,
187 XPATH_OP_VALUE,
188 XPATH_OP_VARIABLE,
189 XPATH_OP_FUNCTION,
190 XPATH_OP_ARG,
191 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000192 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000193 XPATH_OP_SORT
194#ifdef LIBXML_XPTR_ENABLED
195 ,XPATH_OP_RANGETO
196#endif
197} xmlXPathOp;
198
199typedef enum {
200 AXIS_ANCESTOR = 1,
201 AXIS_ANCESTOR_OR_SELF,
202 AXIS_ATTRIBUTE,
203 AXIS_CHILD,
204 AXIS_DESCENDANT,
205 AXIS_DESCENDANT_OR_SELF,
206 AXIS_FOLLOWING,
207 AXIS_FOLLOWING_SIBLING,
208 AXIS_NAMESPACE,
209 AXIS_PARENT,
210 AXIS_PRECEDING,
211 AXIS_PRECEDING_SIBLING,
212 AXIS_SELF
213} xmlXPathAxisVal;
214
215typedef enum {
216 NODE_TEST_NONE = 0,
217 NODE_TEST_TYPE = 1,
218 NODE_TEST_PI = 2,
219 NODE_TEST_ALL = 3,
220 NODE_TEST_NS = 4,
221 NODE_TEST_NAME = 5
222} xmlXPathTestVal;
223
224typedef enum {
225 NODE_TYPE_NODE = 0,
226 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
227 NODE_TYPE_TEXT = XML_TEXT_NODE,
228 NODE_TYPE_PI = XML_PI_NODE
229} xmlXPathTypeVal;
230
231
232typedef struct _xmlXPathStepOp xmlXPathStepOp;
233typedef xmlXPathStepOp *xmlXPathStepOpPtr;
234struct _xmlXPathStepOp {
235 xmlXPathOp op;
236 int ch1;
237 int ch2;
238 int value;
239 int value2;
240 int value3;
241 void *value4;
242 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000243 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000244 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000245};
246
247struct _xmlXPathCompExpr {
248 int nbStep;
249 int maxStep;
250 xmlXPathStepOp *steps; /* ops for computation */
251 int last;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000252#ifdef DEBUG_EVAL_COUNTS
253 int nb;
254 xmlChar *string;
255#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000256};
257
258/************************************************************************
259 * *
260 * Parser Type functions *
261 * *
262 ************************************************************************/
263
264/**
265 * xmlXPathNewCompExpr:
266 *
267 * Create a new Xpath component
268 *
269 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
270 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000271static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000272xmlXPathNewCompExpr(void) {
273 xmlXPathCompExprPtr cur;
274
275 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
276 if (cur == NULL) {
277 xmlGenericError(xmlGenericErrorContext,
278 "xmlXPathNewCompExpr : malloc failed\n");
279 return(NULL);
280 }
281 memset(cur, 0, sizeof(xmlXPathCompExpr));
282 cur->maxStep = 10;
283 cur->nbStep = 0;
284 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
285 sizeof(xmlXPathStepOp));
286 if (cur->steps == NULL) {
287 xmlGenericError(xmlGenericErrorContext,
288 "xmlXPathNewCompExpr : malloc failed\n");
289 xmlFree(cur);
290 return(NULL);
291 }
292 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
293 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000294#ifdef DEBUG_EVAL_COUNTS
295 cur->nb = 0;
296#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000297 return(cur);
298}
299
300/**
301 * xmlXPathFreeCompExpr:
302 * @comp: an XPATH comp
303 *
304 * Free up the memory allocated by @comp
305 */
306void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000307xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
308{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000309 xmlXPathStepOpPtr op;
310 int i;
311
312 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000313 return;
314 for (i = 0; i < comp->nbStep; i++) {
315 op = &comp->steps[i];
316 if (op->value4 != NULL) {
317 if (op->op == XPATH_OP_VALUE)
318 xmlXPathFreeObject(op->value4);
319 else
320 xmlFree(op->value4);
321 }
322 if (op->value5 != NULL)
323 xmlFree(op->value5);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000324 }
325 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000326 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000327 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000328#ifdef DEBUG_EVAL_COUNTS
329 if (comp->string != NULL) {
330 xmlFree(comp->string);
331 }
332#endif
333
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000334 xmlFree(comp);
335}
336
337/**
338 * xmlXPathCompExprAdd:
339 * @comp: the compiled expression
340 * @ch1: first child index
341 * @ch2: second child index
342 * @op: an op
343 * @value: the first int value
344 * @value2: the second int value
345 * @value3: the third int value
346 * @value4: the first string value
347 * @value5: the second string value
348 *
349 * Add an step to an XPath Compiled Expression
350 *
351 * Returns -1 in case of failure, the index otherwise
352 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000353static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000354xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
355 xmlXPathOp op, int value,
356 int value2, int value3, void *value4, void *value5) {
357 if (comp->nbStep >= comp->maxStep) {
358 xmlXPathStepOp *real;
359
360 comp->maxStep *= 2;
361 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
362 comp->maxStep * sizeof(xmlXPathStepOp));
363 if (real == NULL) {
364 comp->maxStep /= 2;
365 xmlGenericError(xmlGenericErrorContext,
366 "xmlXPathCompExprAdd : realloc failed\n");
367 return(-1);
368 }
369 comp->steps = real;
370 }
371 comp->last = comp->nbStep;
372 comp->steps[comp->nbStep].ch1 = ch1;
373 comp->steps[comp->nbStep].ch2 = ch2;
374 comp->steps[comp->nbStep].op = op;
375 comp->steps[comp->nbStep].value = value;
376 comp->steps[comp->nbStep].value2 = value2;
377 comp->steps[comp->nbStep].value3 = value3;
378 comp->steps[comp->nbStep].value4 = value4;
379 comp->steps[comp->nbStep].value5 = value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000380 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000381 return(comp->nbStep++);
382}
383
Daniel Veillardf06307e2001-07-03 10:35:50 +0000384/**
385 * xmlXPathCompSwap:
386 * @comp: the compiled expression
387 * @op: operation index
388 *
389 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000390 */
391static void
392xmlXPathCompSwap(xmlXPathStepOpPtr op) {
393 int tmp;
394
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000395#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000396 /*
397 * Since this manipulates possibly shared variables, this is
398 * disable if one detects that the library is used in a multithreaded
399 * application
400 */
401 if (xmlXPathDisableOptimizer)
402 return;
403#endif
404
Daniel Veillardf06307e2001-07-03 10:35:50 +0000405 tmp = op->ch1;
406 op->ch1 = op->ch2;
407 op->ch2 = tmp;
408}
409
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000410#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
411 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
412 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000413#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
414 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
415 (op), (val), (val2), (val3), (val4), (val5))
416
417#define PUSH_LEAVE_EXPR(op, val, val2) \
418xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
419
420#define PUSH_UNARY_EXPR(op, ch, val, val2) \
421xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
422
423#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
424xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), (val), (val2), 0 ,NULL ,NULL)
425
426/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000427 * *
428 * Debugging related functions *
429 * *
430 ************************************************************************/
431
432#define TODO \
433 xmlGenericError(xmlGenericErrorContext, \
434 "Unimplemented block at %s:%d\n", \
435 __FILE__, __LINE__);
436
437#define STRANGE \
438 xmlGenericError(xmlGenericErrorContext, \
439 "Internal error at %s:%d\n", \
440 __FILE__, __LINE__);
441
442#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000443static void
444xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000445 int i;
446 char shift[100];
447
448 for (i = 0;((i < depth) && (i < 25));i++)
449 shift[2 * i] = shift[2 * i + 1] = ' ';
450 shift[2 * i] = shift[2 * i + 1] = 0;
451 if (cur == NULL) {
452 fprintf(output, shift);
453 fprintf(output, "Node is NULL !\n");
454 return;
455
456 }
457
458 if ((cur->type == XML_DOCUMENT_NODE) ||
459 (cur->type == XML_HTML_DOCUMENT_NODE)) {
460 fprintf(output, shift);
461 fprintf(output, " /\n");
462 } else if (cur->type == XML_ATTRIBUTE_NODE)
463 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
464 else
465 xmlDebugDumpOneNode(output, cur, depth);
466}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000467static void
468xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000469 xmlNodePtr tmp;
470 int i;
471 char shift[100];
472
473 for (i = 0;((i < depth) && (i < 25));i++)
474 shift[2 * i] = shift[2 * i + 1] = ' ';
475 shift[2 * i] = shift[2 * i + 1] = 0;
476 if (cur == NULL) {
477 fprintf(output, shift);
478 fprintf(output, "Node is NULL !\n");
479 return;
480
481 }
482
483 while (cur != NULL) {
484 tmp = cur;
485 cur = cur->next;
486 xmlDebugDumpOneNode(output, tmp, depth);
487 }
488}
Owen Taylor3473f882001-02-23 17:55:21 +0000489
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000490static void
491xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000492 int i;
493 char shift[100];
494
495 for (i = 0;((i < depth) && (i < 25));i++)
496 shift[2 * i] = shift[2 * i + 1] = ' ';
497 shift[2 * i] = shift[2 * i + 1] = 0;
498
499 if (cur == NULL) {
500 fprintf(output, shift);
501 fprintf(output, "NodeSet is NULL !\n");
502 return;
503
504 }
505
Daniel Veillard911f49a2001-04-07 15:39:35 +0000506 if (cur != NULL) {
507 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
508 for (i = 0;i < cur->nodeNr;i++) {
509 fprintf(output, shift);
510 fprintf(output, "%d", i + 1);
511 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
512 }
Owen Taylor3473f882001-02-23 17:55:21 +0000513 }
514}
515
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000516static void
517xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000518 int i;
519 char shift[100];
520
521 for (i = 0;((i < depth) && (i < 25));i++)
522 shift[2 * i] = shift[2 * i + 1] = ' ';
523 shift[2 * i] = shift[2 * i + 1] = 0;
524
525 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
526 fprintf(output, shift);
527 fprintf(output, "Value Tree is NULL !\n");
528 return;
529
530 }
531
532 fprintf(output, shift);
533 fprintf(output, "%d", i + 1);
534 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
535}
Owen Taylor3473f882001-02-23 17:55:21 +0000536#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000537static void
538xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000539 int i;
540 char shift[100];
541
542 for (i = 0;((i < depth) && (i < 25));i++)
543 shift[2 * i] = shift[2 * i + 1] = ' ';
544 shift[2 * i] = shift[2 * i + 1] = 0;
545
546 if (cur == NULL) {
547 fprintf(output, shift);
548 fprintf(output, "LocationSet is NULL !\n");
549 return;
550
551 }
552
553 for (i = 0;i < cur->locNr;i++) {
554 fprintf(output, shift);
555 fprintf(output, "%d : ", i + 1);
556 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
557 }
558}
Daniel Veillard017b1082001-06-21 11:20:21 +0000559#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000560
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000561/**
562 * xmlXPathDebugDumpObject:
563 * @output: the FILE * to dump the output
564 * @cur: the object to inspect
565 * @depth: indentation level
566 *
567 * Dump the content of the object for debugging purposes
568 */
569void
570xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000571 int i;
572 char shift[100];
573
574 for (i = 0;((i < depth) && (i < 25));i++)
575 shift[2 * i] = shift[2 * i + 1] = ' ';
576 shift[2 * i] = shift[2 * i + 1] = 0;
577
578 fprintf(output, shift);
579
580 if (cur == NULL) {
581 fprintf(output, "Object is empty (NULL)\n");
582 return;
583 }
584 switch(cur->type) {
585 case XPATH_UNDEFINED:
586 fprintf(output, "Object is uninitialized\n");
587 break;
588 case XPATH_NODESET:
589 fprintf(output, "Object is a Node Set :\n");
590 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
591 break;
592 case XPATH_XSLT_TREE:
593 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000594 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000595 break;
596 case XPATH_BOOLEAN:
597 fprintf(output, "Object is a Boolean : ");
598 if (cur->boolval) fprintf(output, "true\n");
599 else fprintf(output, "false\n");
600 break;
601 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +0000602 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000603 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000604 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000605 break;
606 case -1:
607 fprintf(output, "Object is a number : -Infinity\n");
608 break;
609 default:
Daniel Veillardcda96922001-08-21 10:56:31 +0000610 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000611 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +0000612 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
613 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000614 } else {
615 fprintf(output, "Object is a number : %0g\n", cur->floatval);
616 }
617 }
Owen Taylor3473f882001-02-23 17:55:21 +0000618 break;
619 case XPATH_STRING:
620 fprintf(output, "Object is a string : ");
621 xmlDebugDumpString(output, cur->stringval);
622 fprintf(output, "\n");
623 break;
624 case XPATH_POINT:
625 fprintf(output, "Object is a point : index %d in node", cur->index);
626 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
627 fprintf(output, "\n");
628 break;
629 case XPATH_RANGE:
630 if ((cur->user2 == NULL) ||
631 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
632 fprintf(output, "Object is a collapsed range :\n");
633 fprintf(output, shift);
634 if (cur->index >= 0)
635 fprintf(output, "index %d in ", cur->index);
636 fprintf(output, "node\n");
637 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
638 depth + 1);
639 } else {
640 fprintf(output, "Object is a range :\n");
641 fprintf(output, shift);
642 fprintf(output, "From ");
643 if (cur->index >= 0)
644 fprintf(output, "index %d in ", cur->index);
645 fprintf(output, "node\n");
646 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
647 depth + 1);
648 fprintf(output, shift);
649 fprintf(output, "To ");
650 if (cur->index2 >= 0)
651 fprintf(output, "index %d in ", cur->index2);
652 fprintf(output, "node\n");
653 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
654 depth + 1);
655 fprintf(output, "\n");
656 }
657 break;
658 case XPATH_LOCATIONSET:
659#if defined(LIBXML_XPTR_ENABLED)
660 fprintf(output, "Object is a Location Set:\n");
661 xmlXPathDebugDumpLocationSet(output,
662 (xmlLocationSetPtr) cur->user, depth);
663#endif
664 break;
665 case XPATH_USERS:
666 fprintf(output, "Object is user defined\n");
667 break;
668 }
669}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000670
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000671static void
672xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000673 xmlXPathStepOpPtr op, int depth) {
674 int i;
675 char shift[100];
676
677 for (i = 0;((i < depth) && (i < 25));i++)
678 shift[2 * i] = shift[2 * i + 1] = ' ';
679 shift[2 * i] = shift[2 * i + 1] = 0;
680
681 fprintf(output, shift);
682 if (op == NULL) {
683 fprintf(output, "Step is NULL\n");
684 return;
685 }
686 switch (op->op) {
687 case XPATH_OP_END:
688 fprintf(output, "END"); break;
689 case XPATH_OP_AND:
690 fprintf(output, "AND"); break;
691 case XPATH_OP_OR:
692 fprintf(output, "OR"); break;
693 case XPATH_OP_EQUAL:
694 if (op->value)
695 fprintf(output, "EQUAL =");
696 else
697 fprintf(output, "EQUAL !=");
698 break;
699 case XPATH_OP_CMP:
700 if (op->value)
701 fprintf(output, "CMP <");
702 else
703 fprintf(output, "CMP >");
704 if (!op->value2)
705 fprintf(output, "=");
706 break;
707 case XPATH_OP_PLUS:
708 if (op->value == 0)
709 fprintf(output, "PLUS -");
710 else if (op->value == 1)
711 fprintf(output, "PLUS +");
712 else if (op->value == 2)
713 fprintf(output, "PLUS unary -");
714 else if (op->value == 3)
715 fprintf(output, "PLUS unary - -");
716 break;
717 case XPATH_OP_MULT:
718 if (op->value == 0)
719 fprintf(output, "MULT *");
720 else if (op->value == 1)
721 fprintf(output, "MULT div");
722 else
723 fprintf(output, "MULT mod");
724 break;
725 case XPATH_OP_UNION:
726 fprintf(output, "UNION"); break;
727 case XPATH_OP_ROOT:
728 fprintf(output, "ROOT"); break;
729 case XPATH_OP_NODE:
730 fprintf(output, "NODE"); break;
731 case XPATH_OP_RESET:
732 fprintf(output, "RESET"); break;
733 case XPATH_OP_SORT:
734 fprintf(output, "SORT"); break;
735 case XPATH_OP_COLLECT: {
736 xmlXPathAxisVal axis = op->value;
737 xmlXPathTestVal test = op->value2;
738 xmlXPathTypeVal type = op->value3;
739 const xmlChar *prefix = op->value4;
740 const xmlChar *name = op->value5;
741
742 fprintf(output, "COLLECT ");
743 switch (axis) {
744 case AXIS_ANCESTOR:
745 fprintf(output, " 'ancestors' "); break;
746 case AXIS_ANCESTOR_OR_SELF:
747 fprintf(output, " 'ancestors-or-self' "); break;
748 case AXIS_ATTRIBUTE:
749 fprintf(output, " 'attributes' "); break;
750 case AXIS_CHILD:
751 fprintf(output, " 'child' "); break;
752 case AXIS_DESCENDANT:
753 fprintf(output, " 'descendant' "); break;
754 case AXIS_DESCENDANT_OR_SELF:
755 fprintf(output, " 'descendant-or-self' "); break;
756 case AXIS_FOLLOWING:
757 fprintf(output, " 'following' "); break;
758 case AXIS_FOLLOWING_SIBLING:
759 fprintf(output, " 'following-siblings' "); break;
760 case AXIS_NAMESPACE:
761 fprintf(output, " 'namespace' "); break;
762 case AXIS_PARENT:
763 fprintf(output, " 'parent' "); break;
764 case AXIS_PRECEDING:
765 fprintf(output, " 'preceding' "); break;
766 case AXIS_PRECEDING_SIBLING:
767 fprintf(output, " 'preceding-sibling' "); break;
768 case AXIS_SELF:
769 fprintf(output, " 'self' "); break;
770 }
771 switch (test) {
772 case NODE_TEST_NONE:
773 fprintf(output, "'none' "); break;
774 case NODE_TEST_TYPE:
775 fprintf(output, "'type' "); break;
776 case NODE_TEST_PI:
777 fprintf(output, "'PI' "); break;
778 case NODE_TEST_ALL:
779 fprintf(output, "'all' "); break;
780 case NODE_TEST_NS:
781 fprintf(output, "'namespace' "); break;
782 case NODE_TEST_NAME:
783 fprintf(output, "'name' "); break;
784 }
785 switch (type) {
786 case NODE_TYPE_NODE:
787 fprintf(output, "'node' "); break;
788 case NODE_TYPE_COMMENT:
789 fprintf(output, "'comment' "); break;
790 case NODE_TYPE_TEXT:
791 fprintf(output, "'text' "); break;
792 case NODE_TYPE_PI:
793 fprintf(output, "'PI' "); break;
794 }
795 if (prefix != NULL)
796 fprintf(output, "%s:", prefix);
797 if (name != NULL)
798 fprintf(output, "%s", name);
799 break;
800
801 }
802 case XPATH_OP_VALUE: {
803 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
804
805 fprintf(output, "ELEM ");
806 xmlXPathDebugDumpObject(output, object, 0);
807 goto finish;
808 }
809 case XPATH_OP_VARIABLE: {
810 const xmlChar *prefix = op->value5;
811 const xmlChar *name = op->value4;
812
813 if (prefix != NULL)
814 fprintf(output, "VARIABLE %s:%s", prefix, name);
815 else
816 fprintf(output, "VARIABLE %s", name);
817 break;
818 }
819 case XPATH_OP_FUNCTION: {
820 int nbargs = op->value;
821 const xmlChar *prefix = op->value5;
822 const xmlChar *name = op->value4;
823
824 if (prefix != NULL)
825 fprintf(output, "FUNCTION %s:%s(%d args)",
826 prefix, name, nbargs);
827 else
828 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
829 break;
830 }
831 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
832 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000833 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +0000834#ifdef LIBXML_XPTR_ENABLED
835 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
836#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000837 default:
838 fprintf(output, "UNKNOWN %d\n", op->op); return;
839 }
840 fprintf(output, "\n");
841finish:
842 if (op->ch1 >= 0)
843 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
844 if (op->ch2 >= 0)
845 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
846}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000847
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000848/**
849 * xmlXPathDebugDumpCompExpr:
850 * @output: the FILE * for the output
851 * @comp: the precompiled XPath expression
852 * @depth: the indentation level.
853 *
854 * Dumps the tree of the compiled XPath expression.
855 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000856void
857xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
858 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000859 int i;
860 char shift[100];
861
862 for (i = 0;((i < depth) && (i < 25));i++)
863 shift[2 * i] = shift[2 * i + 1] = ' ';
864 shift[2 * i] = shift[2 * i + 1] = 0;
865
866 fprintf(output, shift);
867
868 if (comp == NULL) {
869 fprintf(output, "Compiled Expression is NULL\n");
870 return;
871 }
872 fprintf(output, "Compiled Expression : %d elements\n",
873 comp->nbStep);
874 i = comp->last;
875 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
876}
Daniel Veillard017b1082001-06-21 11:20:21 +0000877#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000878
879/************************************************************************
880 * *
881 * Parser stacks related functions and macros *
882 * *
883 ************************************************************************/
884
885/*
886 * Generic function for accessing stacks in the Parser Context
887 */
888
889#define PUSH_AND_POP(type, name) \
890extern int name##Push(xmlXPathParserContextPtr ctxt, type value) { \
891 if (ctxt->name##Nr >= ctxt->name##Max) { \
892 ctxt->name##Max *= 2; \
893 ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab, \
894 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
895 if (ctxt->name##Tab == NULL) { \
896 xmlGenericError(xmlGenericErrorContext, \
897 "realloc failed !\n"); \
898 return(0); \
899 } \
900 } \
901 ctxt->name##Tab[ctxt->name##Nr] = value; \
902 ctxt->name = value; \
903 return(ctxt->name##Nr++); \
904} \
905extern type name##Pop(xmlXPathParserContextPtr ctxt) { \
906 type ret; \
907 if (ctxt->name##Nr <= 0) return(0); \
908 ctxt->name##Nr--; \
909 if (ctxt->name##Nr > 0) \
910 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
911 else \
912 ctxt->name = NULL; \
913 ret = ctxt->name##Tab[ctxt->name##Nr]; \
914 ctxt->name##Tab[ctxt->name##Nr] = 0; \
915 return(ret); \
916} \
917
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000918/**
919 * valuePop:
920 * @ctxt: an XPath evaluation context
921 *
922 * Pops the top XPath object from the value stack
923 *
924 * Returns the XPath object just removed
925 */
926/**
927 * valuePush:
928 * @ctxt: an XPath evaluation context
929 * @value: the XPath object
930 *
931 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000932 *
933 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000934 */
Owen Taylor3473f882001-02-23 17:55:21 +0000935PUSH_AND_POP(xmlXPathObjectPtr, value)
936
Thomas Broyerf06a3d82001-07-16 04:52:57 +0000937/**
938 * xmlXPathPopBoolean:
939 * @ctxt: an XPath parser context
940 *
941 * Pops a boolean from the stack, handling conversion if needed.
942 * Check error with #xmlXPathCheckError.
943 *
944 * Returns the boolean
945 */
946int
947xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
948 xmlXPathObjectPtr obj;
949 int ret;
950
951 obj = valuePop(ctxt);
952 if (obj == NULL) {
953 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
954 return(0);
955 }
956 ret = xmlXPathCastToBoolean(obj);
957 xmlXPathFreeObject(obj);
958 return(ret);
959}
960
961/**
962 * xmlXPathPopNumber:
963 * @ctxt: an XPath parser context
964 *
965 * Pops a number from the stack, handling conversion if needed.
966 * Check error with #xmlXPathCheckError.
967 *
968 * Returns the number
969 */
970double
971xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
972 xmlXPathObjectPtr obj;
973 double ret;
974
975 obj = valuePop(ctxt);
976 if (obj == NULL) {
977 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
978 return(0);
979 }
980 ret = xmlXPathCastToNumber(obj);
981 xmlXPathFreeObject(obj);
982 return(ret);
983}
984
985/**
986 * xmlXPathPopString:
987 * @ctxt: an XPath parser context
988 *
989 * Pops a string from the stack, handling conversion if needed.
990 * Check error with #xmlXPathCheckError.
991 *
992 * Returns the string
993 */
994xmlChar *
995xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
996 xmlXPathObjectPtr obj;
997 xmlChar * ret;
998
999 obj = valuePop(ctxt);
1000 if (obj == NULL) {
1001 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1002 return(NULL);
1003 }
1004 ret = xmlXPathCastToString(obj);
1005 /* TODO: needs refactoring somewhere else */
1006 if (obj->stringval == ret)
1007 obj->stringval = NULL;
1008 xmlXPathFreeObject(obj);
1009 return(ret);
1010}
1011
1012/**
1013 * xmlXPathPopNodeSet:
1014 * @ctxt: an XPath parser context
1015 *
1016 * Pops a node-set from the stack, handling conversion if needed.
1017 * Check error with #xmlXPathCheckError.
1018 *
1019 * Returns the node-set
1020 */
1021xmlNodeSetPtr
1022xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
1023 xmlXPathObjectPtr obj;
1024 xmlNodeSetPtr ret;
1025
1026 if (ctxt->value == NULL) {
1027 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1028 return(NULL);
1029 }
1030 if (!xmlXPathStackIsNodeSet(ctxt)) {
1031 xmlXPathSetTypeError(ctxt);
1032 return(NULL);
1033 }
1034 obj = valuePop(ctxt);
1035 ret = obj->nodesetval;
1036 xmlXPathFreeNodeSetList(obj);
1037 return(ret);
1038}
1039
1040/**
1041 * xmlXPathPopExternal:
1042 * @ctxt: an XPath parser context
1043 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001044 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001045 * Check error with #xmlXPathCheckError.
1046 *
1047 * Returns the object
1048 */
1049void *
1050xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1051 xmlXPathObjectPtr obj;
1052 void * ret;
1053
1054 if (ctxt->value == NULL) {
1055 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1056 return(NULL);
1057 }
1058 if (ctxt->value->type != XPATH_USERS) {
1059 xmlXPathSetTypeError(ctxt);
1060 return(NULL);
1061 }
1062 obj = valuePop(ctxt);
1063 ret = obj->user;
1064 xmlXPathFreeObject(obj);
1065 return(ret);
1066}
1067
Owen Taylor3473f882001-02-23 17:55:21 +00001068/*
1069 * Macros for accessing the content. Those should be used only by the parser,
1070 * and not exported.
1071 *
1072 * Dirty macros, i.e. one need to make assumption on the context to use them
1073 *
1074 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1075 * CUR returns the current xmlChar value, i.e. a 8 bit value
1076 * in ISO-Latin or UTF-8.
1077 * This should be used internally by the parser
1078 * only to compare to ASCII values otherwise it would break when
1079 * running with UTF-8 encoding.
1080 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1081 * to compare on ASCII based substring.
1082 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1083 * strings within the parser.
1084 * CURRENT Returns the current char value, with the full decoding of
1085 * UTF-8 if we are using this mode. It returns an int.
1086 * NEXT Skip to the next character, this does the proper decoding
1087 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1088 * It returns the pointer to the current xmlChar.
1089 */
1090
1091#define CUR (*ctxt->cur)
1092#define SKIP(val) ctxt->cur += (val)
1093#define NXT(val) ctxt->cur[(val)]
1094#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001095#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1096
1097#define COPY_BUF(l,b,i,v) \
1098 if (l == 1) b[i++] = (xmlChar) v; \
1099 else i += xmlCopyChar(l,&b[i],v)
1100
1101#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001102
1103#define SKIP_BLANKS \
1104 while (IS_BLANK(*(ctxt->cur))) NEXT
1105
1106#define CURRENT (*ctxt->cur)
1107#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1108
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001109
1110#ifndef DBL_DIG
1111#define DBL_DIG 16
1112#endif
1113#ifndef DBL_EPSILON
1114#define DBL_EPSILON 1E-9
1115#endif
1116
1117#define UPPER_DOUBLE 1E9
1118#define LOWER_DOUBLE 1E-5
1119
1120#define INTEGER_DIGITS DBL_DIG
1121#define FRACTION_DIGITS (DBL_DIG + 1)
1122#define EXPONENT_DIGITS (3 + 2)
1123
1124/**
1125 * xmlXPathFormatNumber:
1126 * @number: number to format
1127 * @buffer: output buffer
1128 * @buffersize: size of output buffer
1129 *
1130 * Convert the number into a string representation.
1131 */
1132static void
1133xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1134{
Daniel Veillardcda96922001-08-21 10:56:31 +00001135 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001136 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001137 if (buffersize > (int)sizeof("Infinity"))
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) {
Daniel Veillard23b1f372002-04-18 15:50:05 +00003219 if ((node != NULL) && (node->type == XML_DOCUMENT_NODE))
3220 node = xmlDocGetRootElement((xmlDocPtr) node);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003221 return(xmlNodeGetContent(node));
3222}
3223
3224/**
3225 * xmlXPathCastNodeSetToString:
3226 * @ns: a node-set
3227 *
3228 * Converts a node-set to its string value.
3229 *
3230 * Returns a newly allocated string.
3231 */
3232xmlChar *
3233xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3234 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3235 return(xmlStrdup((const xmlChar *) ""));
3236
3237 xmlXPathNodeSetSort(ns);
3238 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3239}
3240
3241/**
3242 * xmlXPathCastToString:
3243 * @val: an XPath object
3244 *
3245 * Converts an existing object to its string() equivalent
3246 *
3247 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003248 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003249 * string object).
3250 */
3251xmlChar *
3252xmlXPathCastToString(xmlXPathObjectPtr val) {
3253 xmlChar *ret = NULL;
3254
3255 if (val == NULL)
3256 return(xmlStrdup((const xmlChar *) ""));
3257 switch (val->type) {
3258 case XPATH_UNDEFINED:
3259#ifdef DEBUG_EXPR
3260 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3261#endif
3262 ret = xmlStrdup((const xmlChar *) "");
3263 break;
3264 case XPATH_XSLT_TREE:
3265 case XPATH_NODESET:
3266 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3267 break;
3268 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00003269 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003270 case XPATH_BOOLEAN:
3271 ret = xmlXPathCastBooleanToString(val->boolval);
3272 break;
3273 case XPATH_NUMBER: {
3274 ret = xmlXPathCastNumberToString(val->floatval);
3275 break;
3276 }
3277 case XPATH_USERS:
3278 case XPATH_POINT:
3279 case XPATH_RANGE:
3280 case XPATH_LOCATIONSET:
3281 TODO
3282 ret = xmlStrdup((const xmlChar *) "");
3283 break;
3284 }
3285 return(ret);
3286}
3287
3288/**
3289 * xmlXPathConvertString:
3290 * @val: an XPath object
3291 *
3292 * Converts an existing object to its string() equivalent
3293 *
3294 * Returns the new object, the old one is freed (or the operation
3295 * is done directly on @val)
3296 */
3297xmlXPathObjectPtr
3298xmlXPathConvertString(xmlXPathObjectPtr val) {
3299 xmlChar *res = NULL;
3300
3301 if (val == NULL)
3302 return(xmlXPathNewCString(""));
3303
3304 switch (val->type) {
3305 case XPATH_UNDEFINED:
3306#ifdef DEBUG_EXPR
3307 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3308#endif
3309 break;
3310 case XPATH_XSLT_TREE:
3311 case XPATH_NODESET:
3312 res = xmlXPathCastNodeSetToString(val->nodesetval);
3313 break;
3314 case XPATH_STRING:
3315 return(val);
3316 case XPATH_BOOLEAN:
3317 res = xmlXPathCastBooleanToString(val->boolval);
3318 break;
3319 case XPATH_NUMBER:
3320 res = xmlXPathCastNumberToString(val->floatval);
3321 break;
3322 case XPATH_USERS:
3323 case XPATH_POINT:
3324 case XPATH_RANGE:
3325 case XPATH_LOCATIONSET:
3326 TODO;
3327 break;
3328 }
3329 xmlXPathFreeObject(val);
3330 if (res == NULL)
3331 return(xmlXPathNewCString(""));
3332 return(xmlXPathWrapString(res));
3333}
3334
3335/**
3336 * xmlXPathCastBooleanToNumber:
3337 * @val: a boolean
3338 *
3339 * Converts a boolean to its number value
3340 *
3341 * Returns the number value
3342 */
3343double
3344xmlXPathCastBooleanToNumber(int val) {
3345 if (val)
3346 return(1.0);
3347 return(0.0);
3348}
3349
3350/**
3351 * xmlXPathCastStringToNumber:
3352 * @val: a string
3353 *
3354 * Converts a string to its number value
3355 *
3356 * Returns the number value
3357 */
3358double
3359xmlXPathCastStringToNumber(const xmlChar * val) {
3360 return(xmlXPathStringEvalNumber(val));
3361}
3362
3363/**
3364 * xmlXPathCastNodeToNumber:
3365 * @node: a node
3366 *
3367 * Converts a node to its number value
3368 *
3369 * Returns the number value
3370 */
3371double
3372xmlXPathCastNodeToNumber (xmlNodePtr node) {
3373 xmlChar *strval;
3374 double ret;
3375
3376 if (node == NULL)
3377 return(xmlXPathNAN);
3378 strval = xmlXPathCastNodeToString(node);
3379 if (strval == NULL)
3380 return(xmlXPathNAN);
3381 ret = xmlXPathCastStringToNumber(strval);
3382 xmlFree(strval);
3383
3384 return(ret);
3385}
3386
3387/**
3388 * xmlXPathCastNodeSetToNumber:
3389 * @ns: a node-set
3390 *
3391 * Converts a node-set to its number value
3392 *
3393 * Returns the number value
3394 */
3395double
3396xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3397 xmlChar *str;
3398 double ret;
3399
3400 if (ns == NULL)
3401 return(xmlXPathNAN);
3402 str = xmlXPathCastNodeSetToString(ns);
3403 ret = xmlXPathCastStringToNumber(str);
3404 xmlFree(str);
3405 return(ret);
3406}
3407
3408/**
3409 * xmlXPathCastToNumber:
3410 * @val: an XPath object
3411 *
3412 * Converts an XPath object to its number value
3413 *
3414 * Returns the number value
3415 */
3416double
3417xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3418 double ret = 0.0;
3419
3420 if (val == NULL)
3421 return(xmlXPathNAN);
3422 switch (val->type) {
3423 case XPATH_UNDEFINED:
3424#ifdef DEGUB_EXPR
3425 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3426#endif
3427 ret = xmlXPathNAN;
3428 break;
3429 case XPATH_XSLT_TREE:
3430 case XPATH_NODESET:
3431 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3432 break;
3433 case XPATH_STRING:
3434 ret = xmlXPathCastStringToNumber(val->stringval);
3435 break;
3436 case XPATH_NUMBER:
3437 ret = val->floatval;
3438 break;
3439 case XPATH_BOOLEAN:
3440 ret = xmlXPathCastBooleanToNumber(val->boolval);
3441 break;
3442 case XPATH_USERS:
3443 case XPATH_POINT:
3444 case XPATH_RANGE:
3445 case XPATH_LOCATIONSET:
3446 TODO;
3447 ret = xmlXPathNAN;
3448 break;
3449 }
3450 return(ret);
3451}
3452
3453/**
3454 * xmlXPathConvertNumber:
3455 * @val: an XPath object
3456 *
3457 * Converts an existing object to its number() equivalent
3458 *
3459 * Returns the new object, the old one is freed (or the operation
3460 * is done directly on @val)
3461 */
3462xmlXPathObjectPtr
3463xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3464 xmlXPathObjectPtr ret;
3465
3466 if (val == NULL)
3467 return(xmlXPathNewFloat(0.0));
3468 if (val->type == XPATH_NUMBER)
3469 return(val);
3470 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3471 xmlXPathFreeObject(val);
3472 return(ret);
3473}
3474
3475/**
3476 * xmlXPathCastNumberToBoolean:
3477 * @val: a number
3478 *
3479 * Converts a number to its boolean value
3480 *
3481 * Returns the boolean value
3482 */
3483int
3484xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003485 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003486 return(0);
3487 return(1);
3488}
3489
3490/**
3491 * xmlXPathCastStringToBoolean:
3492 * @val: a string
3493 *
3494 * Converts a string to its boolean value
3495 *
3496 * Returns the boolean value
3497 */
3498int
3499xmlXPathCastStringToBoolean (const xmlChar *val) {
3500 if ((val == NULL) || (xmlStrlen(val) == 0))
3501 return(0);
3502 return(1);
3503}
3504
3505/**
3506 * xmlXPathCastNodeSetToBoolean:
3507 * @ns: a node-set
3508 *
3509 * Converts a node-set to its boolean value
3510 *
3511 * Returns the boolean value
3512 */
3513int
3514xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3515 if ((ns == NULL) || (ns->nodeNr == 0))
3516 return(0);
3517 return(1);
3518}
3519
3520/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003521 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003522 * @val: an XPath object
3523 *
3524 * Converts an XPath object to its boolean value
3525 *
3526 * Returns the boolean value
3527 */
3528int
3529xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3530 int ret = 0;
3531
3532 if (val == NULL)
3533 return(0);
3534 switch (val->type) {
3535 case XPATH_UNDEFINED:
3536#ifdef DEBUG_EXPR
3537 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3538#endif
3539 ret = 0;
3540 break;
3541 case XPATH_XSLT_TREE:
3542 case XPATH_NODESET:
3543 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3544 break;
3545 case XPATH_STRING:
3546 ret = xmlXPathCastStringToBoolean(val->stringval);
3547 break;
3548 case XPATH_NUMBER:
3549 ret = xmlXPathCastNumberToBoolean(val->floatval);
3550 break;
3551 case XPATH_BOOLEAN:
3552 ret = val->boolval;
3553 break;
3554 case XPATH_USERS:
3555 case XPATH_POINT:
3556 case XPATH_RANGE:
3557 case XPATH_LOCATIONSET:
3558 TODO;
3559 ret = 0;
3560 break;
3561 }
3562 return(ret);
3563}
3564
3565
3566/**
3567 * xmlXPathConvertBoolean:
3568 * @val: an XPath object
3569 *
3570 * Converts an existing object to its boolean() equivalent
3571 *
3572 * Returns the new object, the old one is freed (or the operation
3573 * is done directly on @val)
3574 */
3575xmlXPathObjectPtr
3576xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3577 xmlXPathObjectPtr ret;
3578
3579 if (val == NULL)
3580 return(xmlXPathNewBoolean(0));
3581 if (val->type == XPATH_BOOLEAN)
3582 return(val);
3583 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3584 xmlXPathFreeObject(val);
3585 return(ret);
3586}
3587
Owen Taylor3473f882001-02-23 17:55:21 +00003588/************************************************************************
3589 * *
3590 * Routines to handle XPath contexts *
3591 * *
3592 ************************************************************************/
3593
3594/**
3595 * xmlXPathNewContext:
3596 * @doc: the XML document
3597 *
3598 * Create a new xmlXPathContext
3599 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00003600 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00003601 */
3602xmlXPathContextPtr
3603xmlXPathNewContext(xmlDocPtr doc) {
3604 xmlXPathContextPtr ret;
3605
3606 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3607 if (ret == NULL) {
3608 xmlGenericError(xmlGenericErrorContext,
3609 "xmlXPathNewContext: out of memory\n");
3610 return(NULL);
3611 }
3612 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3613 ret->doc = doc;
3614 ret->node = NULL;
3615
3616 ret->varHash = NULL;
3617
3618 ret->nb_types = 0;
3619 ret->max_types = 0;
3620 ret->types = NULL;
3621
3622 ret->funcHash = xmlHashCreate(0);
3623
3624 ret->nb_axis = 0;
3625 ret->max_axis = 0;
3626 ret->axis = NULL;
3627
3628 ret->nsHash = NULL;
3629 ret->user = NULL;
3630
3631 ret->contextSize = -1;
3632 ret->proximityPosition = -1;
3633
3634 xmlXPathRegisterAllFunctions(ret);
3635
3636 return(ret);
3637}
3638
3639/**
3640 * xmlXPathFreeContext:
3641 * @ctxt: the context to free
3642 *
3643 * Free up an xmlXPathContext
3644 */
3645void
3646xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3647 xmlXPathRegisteredNsCleanup(ctxt);
3648 xmlXPathRegisteredFuncsCleanup(ctxt);
3649 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003650 xmlFree(ctxt);
3651}
3652
3653/************************************************************************
3654 * *
3655 * Routines to handle XPath parser contexts *
3656 * *
3657 ************************************************************************/
3658
3659#define CHECK_CTXT(ctxt) \
3660 if (ctxt == NULL) { \
3661 xmlGenericError(xmlGenericErrorContext, \
3662 "%s:%d Internal error: ctxt == NULL\n", \
3663 __FILE__, __LINE__); \
3664 } \
3665
3666
3667#define CHECK_CONTEXT(ctxt) \
3668 if (ctxt == NULL) { \
3669 xmlGenericError(xmlGenericErrorContext, \
3670 "%s:%d Internal error: no context\n", \
3671 __FILE__, __LINE__); \
3672 } \
3673 else if (ctxt->doc == NULL) { \
3674 xmlGenericError(xmlGenericErrorContext, \
3675 "%s:%d Internal error: no document\n", \
3676 __FILE__, __LINE__); \
3677 } \
3678 else if (ctxt->doc->children == NULL) { \
3679 xmlGenericError(xmlGenericErrorContext, \
3680 "%s:%d Internal error: document without root\n", \
3681 __FILE__, __LINE__); \
3682 } \
3683
3684
3685/**
3686 * xmlXPathNewParserContext:
3687 * @str: the XPath expression
3688 * @ctxt: the XPath context
3689 *
3690 * Create a new xmlXPathParserContext
3691 *
3692 * Returns the xmlXPathParserContext just allocated.
3693 */
3694xmlXPathParserContextPtr
3695xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3696 xmlXPathParserContextPtr ret;
3697
3698 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3699 if (ret == NULL) {
3700 xmlGenericError(xmlGenericErrorContext,
3701 "xmlXPathNewParserContext: out of memory\n");
3702 return(NULL);
3703 }
3704 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3705 ret->cur = ret->base = str;
3706 ret->context = ctxt;
3707
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003708 ret->comp = xmlXPathNewCompExpr();
3709 if (ret->comp == NULL) {
3710 xmlFree(ret->valueTab);
3711 xmlFree(ret);
3712 return(NULL);
3713 }
3714
3715 return(ret);
3716}
3717
3718/**
3719 * xmlXPathCompParserContext:
3720 * @comp: the XPath compiled expression
3721 * @ctxt: the XPath context
3722 *
3723 * Create a new xmlXPathParserContext when processing a compiled expression
3724 *
3725 * Returns the xmlXPathParserContext just allocated.
3726 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003727static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003728xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3729 xmlXPathParserContextPtr ret;
3730
3731 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3732 if (ret == NULL) {
3733 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003734 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003735 return(NULL);
3736 }
3737 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3738
Owen Taylor3473f882001-02-23 17:55:21 +00003739 /* Allocate the value stack */
3740 ret->valueTab = (xmlXPathObjectPtr *)
3741 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003742 if (ret->valueTab == NULL) {
3743 xmlFree(ret);
3744 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003745 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003746 return(NULL);
3747 }
Owen Taylor3473f882001-02-23 17:55:21 +00003748 ret->valueNr = 0;
3749 ret->valueMax = 10;
3750 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003751
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00003752 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003753 ret->comp = comp;
3754
Owen Taylor3473f882001-02-23 17:55:21 +00003755 return(ret);
3756}
3757
3758/**
3759 * xmlXPathFreeParserContext:
3760 * @ctxt: the context to free
3761 *
3762 * Free up an xmlXPathParserContext
3763 */
3764void
3765xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
3766 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003767 xmlFree(ctxt->valueTab);
3768 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003769 if (ctxt->comp)
3770 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00003771 xmlFree(ctxt);
3772}
3773
3774/************************************************************************
3775 * *
3776 * The implicit core function library *
3777 * *
3778 ************************************************************************/
3779
Owen Taylor3473f882001-02-23 17:55:21 +00003780/**
Daniel Veillardf06307e2001-07-03 10:35:50 +00003781 * xmlXPathNodeStringHash:
3782 * @node: a node pointer
3783 *
3784 * Function computing the beginning of the string value of the node,
3785 * used to speed up comparisons
3786 *
3787 * Returns an int usable as a hash
3788 */
3789static unsigned int
3790xmlXPathNodeValHash(xmlNodePtr node) {
3791 int len = 2;
3792 const xmlChar * string = NULL;
3793 xmlNodePtr tmp = NULL;
3794 unsigned int ret = 0;
3795
3796 if (node == NULL)
3797 return(0);
3798
3799
3800 switch (node->type) {
3801 case XML_COMMENT_NODE:
3802 case XML_PI_NODE:
3803 case XML_CDATA_SECTION_NODE:
3804 case XML_TEXT_NODE:
3805 string = node->content;
3806 if (string == NULL)
3807 return(0);
3808 if (string[0] == 0)
3809 return(0);
3810 return(((unsigned int) string[0]) +
3811 (((unsigned int) string[1]) << 8));
3812 case XML_NAMESPACE_DECL:
3813 string = ((xmlNsPtr)node)->href;
3814 if (string == NULL)
3815 return(0);
3816 if (string[0] == 0)
3817 return(0);
3818 return(((unsigned int) string[0]) +
3819 (((unsigned int) string[1]) << 8));
3820 case XML_ATTRIBUTE_NODE:
3821 tmp = ((xmlAttrPtr) node)->children;
3822 break;
3823 case XML_ELEMENT_NODE:
3824 tmp = node->children;
3825 break;
3826 default:
3827 return(0);
3828 }
3829 while (tmp != NULL) {
3830 switch (tmp->type) {
3831 case XML_COMMENT_NODE:
3832 case XML_PI_NODE:
3833 case XML_CDATA_SECTION_NODE:
3834 case XML_TEXT_NODE:
3835 string = tmp->content;
3836 break;
3837 case XML_NAMESPACE_DECL:
3838 string = ((xmlNsPtr)tmp)->href;
3839 break;
3840 default:
3841 break;
3842 }
3843 if ((string != NULL) && (string[0] != 0)) {
3844 if (string[0] == 0)
3845 return(0);
3846 if (len == 1) {
3847 return(ret + (((unsigned int) string[0]) << 8));
3848 }
3849 if (string[1] == 0) {
3850 len = 1;
3851 ret = (unsigned int) string[0];
3852 } else {
3853 return(((unsigned int) string[0]) +
3854 (((unsigned int) string[1]) << 8));
3855 }
3856 }
3857 /*
3858 * Skip to next node
3859 */
3860 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
3861 if (tmp->children->type != XML_ENTITY_DECL) {
3862 tmp = tmp->children;
3863 continue;
3864 }
3865 }
3866 if (tmp == node)
3867 break;
3868
3869 if (tmp->next != NULL) {
3870 tmp = tmp->next;
3871 continue;
3872 }
3873
3874 do {
3875 tmp = tmp->parent;
3876 if (tmp == NULL)
3877 break;
3878 if (tmp == node) {
3879 tmp = NULL;
3880 break;
3881 }
3882 if (tmp->next != NULL) {
3883 tmp = tmp->next;
3884 break;
3885 }
3886 } while (tmp != NULL);
3887 }
3888 return(ret);
3889}
3890
3891/**
3892 * xmlXPathStringHash:
3893 * @string: a string
3894 *
3895 * Function computing the beginning of the string value of the node,
3896 * used to speed up comparisons
3897 *
3898 * Returns an int usable as a hash
3899 */
3900static unsigned int
3901xmlXPathStringHash(const xmlChar * string) {
3902 if (string == NULL)
3903 return((unsigned int) 0);
3904 if (string[0] == 0)
3905 return(0);
3906 return(((unsigned int) string[0]) +
3907 (((unsigned int) string[1]) << 8));
3908}
3909
3910/**
Owen Taylor3473f882001-02-23 17:55:21 +00003911 * xmlXPathCompareNodeSetFloat:
3912 * @ctxt: the XPath Parser context
3913 * @inf: less than (1) or greater than (0)
3914 * @strict: is the comparison strict
3915 * @arg: the node set
3916 * @f: the value
3917 *
3918 * Implement the compare operation between a nodeset and a number
3919 * @ns < @val (1, 1, ...
3920 * @ns <= @val (1, 0, ...
3921 * @ns > @val (0, 1, ...
3922 * @ns >= @val (0, 0, ...
3923 *
3924 * If one object to be compared is a node-set and the other is a number,
3925 * then the comparison will be true if and only if there is a node in the
3926 * node-set such that the result of performing the comparison on the number
3927 * to be compared and on the result of converting the string-value of that
3928 * node to a number using the number function is true.
3929 *
3930 * Returns 0 or 1 depending on the results of the test.
3931 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003932static int
Owen Taylor3473f882001-02-23 17:55:21 +00003933xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
3934 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
3935 int i, ret = 0;
3936 xmlNodeSetPtr ns;
3937 xmlChar *str2;
3938
3939 if ((f == NULL) || (arg == NULL) ||
3940 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3941 xmlXPathFreeObject(arg);
3942 xmlXPathFreeObject(f);
3943 return(0);
3944 }
3945 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003946 if (ns != NULL) {
3947 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003948 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003949 if (str2 != NULL) {
3950 valuePush(ctxt,
3951 xmlXPathNewString(str2));
3952 xmlFree(str2);
3953 xmlXPathNumberFunction(ctxt, 1);
3954 valuePush(ctxt, xmlXPathObjectCopy(f));
3955 ret = xmlXPathCompareValues(ctxt, inf, strict);
3956 if (ret)
3957 break;
3958 }
3959 }
Owen Taylor3473f882001-02-23 17:55:21 +00003960 }
3961 xmlXPathFreeObject(arg);
3962 xmlXPathFreeObject(f);
3963 return(ret);
3964}
3965
3966/**
3967 * xmlXPathCompareNodeSetString:
3968 * @ctxt: the XPath Parser context
3969 * @inf: less than (1) or greater than (0)
3970 * @strict: is the comparison strict
3971 * @arg: the node set
3972 * @s: the value
3973 *
3974 * Implement the compare operation between a nodeset and a string
3975 * @ns < @val (1, 1, ...
3976 * @ns <= @val (1, 0, ...
3977 * @ns > @val (0, 1, ...
3978 * @ns >= @val (0, 0, ...
3979 *
3980 * If one object to be compared is a node-set and the other is a string,
3981 * then the comparison will be true if and only if there is a node in
3982 * the node-set such that the result of performing the comparison on the
3983 * string-value of the node and the other string is true.
3984 *
3985 * Returns 0 or 1 depending on the results of the test.
3986 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003987static int
Owen Taylor3473f882001-02-23 17:55:21 +00003988xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
3989 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
3990 int i, ret = 0;
3991 xmlNodeSetPtr ns;
3992 xmlChar *str2;
3993
3994 if ((s == NULL) || (arg == NULL) ||
3995 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3996 xmlXPathFreeObject(arg);
3997 xmlXPathFreeObject(s);
3998 return(0);
3999 }
4000 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004001 if (ns != NULL) {
4002 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004003 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004004 if (str2 != NULL) {
4005 valuePush(ctxt,
4006 xmlXPathNewString(str2));
4007 xmlFree(str2);
4008 valuePush(ctxt, xmlXPathObjectCopy(s));
4009 ret = xmlXPathCompareValues(ctxt, inf, strict);
4010 if (ret)
4011 break;
4012 }
4013 }
Owen Taylor3473f882001-02-23 17:55:21 +00004014 }
4015 xmlXPathFreeObject(arg);
4016 xmlXPathFreeObject(s);
4017 return(ret);
4018}
4019
4020/**
4021 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004022 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00004023 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004024 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00004025 * @arg2: the second node set object
4026 *
4027 * Implement the compare operation on nodesets:
4028 *
4029 * If both objects to be compared are node-sets, then the comparison
4030 * will be true if and only if there is a node in the first node-set
4031 * and a node in the second node-set such that the result of performing
4032 * the comparison on the string-values of the two nodes is true.
4033 * ....
4034 * When neither object to be compared is a node-set and the operator
4035 * is <=, <, >= or >, then the objects are compared by converting both
4036 * objects to numbers and comparing the numbers according to IEEE 754.
4037 * ....
4038 * The number function converts its argument to a number as follows:
4039 * - a string that consists of optional whitespace followed by an
4040 * optional minus sign followed by a Number followed by whitespace
4041 * is converted to the IEEE 754 number that is nearest (according
4042 * to the IEEE 754 round-to-nearest rule) to the mathematical value
4043 * represented by the string; any other string is converted to NaN
4044 *
4045 * Conclusion all nodes need to be converted first to their string value
4046 * and then the comparison must be done when possible
4047 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004048static int
4049xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00004050 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4051 int i, j, init = 0;
4052 double val1;
4053 double *values2;
4054 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004055 xmlNodeSetPtr ns1;
4056 xmlNodeSetPtr ns2;
4057
4058 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004059 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4060 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004061 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004062 }
Owen Taylor3473f882001-02-23 17:55:21 +00004063 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004064 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4065 xmlXPathFreeObject(arg1);
4066 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004067 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004068 }
Owen Taylor3473f882001-02-23 17:55:21 +00004069
4070 ns1 = arg1->nodesetval;
4071 ns2 = arg2->nodesetval;
4072
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004073 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004074 xmlXPathFreeObject(arg1);
4075 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004076 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004077 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004078 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004079 xmlXPathFreeObject(arg1);
4080 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004081 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004082 }
Owen Taylor3473f882001-02-23 17:55:21 +00004083
4084 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4085 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004086 xmlXPathFreeObject(arg1);
4087 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004088 return(0);
4089 }
4090 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004091 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004092 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004093 continue;
4094 for (j = 0;j < ns2->nodeNr;j++) {
4095 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004096 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004097 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004098 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004099 continue;
4100 if (inf && strict)
4101 ret = (val1 < values2[j]);
4102 else if (inf && !strict)
4103 ret = (val1 <= values2[j]);
4104 else if (!inf && strict)
4105 ret = (val1 > values2[j]);
4106 else if (!inf && !strict)
4107 ret = (val1 >= values2[j]);
4108 if (ret)
4109 break;
4110 }
4111 if (ret)
4112 break;
4113 init = 1;
4114 }
4115 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004116 xmlXPathFreeObject(arg1);
4117 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004118 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004119}
4120
4121/**
4122 * xmlXPathCompareNodeSetValue:
4123 * @ctxt: the XPath Parser context
4124 * @inf: less than (1) or greater than (0)
4125 * @strict: is the comparison strict
4126 * @arg: the node set
4127 * @val: the value
4128 *
4129 * Implement the compare operation between a nodeset and a value
4130 * @ns < @val (1, 1, ...
4131 * @ns <= @val (1, 0, ...
4132 * @ns > @val (0, 1, ...
4133 * @ns >= @val (0, 0, ...
4134 *
4135 * If one object to be compared is a node-set and the other is a boolean,
4136 * then the comparison will be true if and only if the result of performing
4137 * the comparison on the boolean and on the result of converting
4138 * the node-set to a boolean using the boolean function is true.
4139 *
4140 * Returns 0 or 1 depending on the results of the test.
4141 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004142static int
Owen Taylor3473f882001-02-23 17:55:21 +00004143xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4144 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4145 if ((val == NULL) || (arg == NULL) ||
4146 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4147 return(0);
4148
4149 switch(val->type) {
4150 case XPATH_NUMBER:
4151 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4152 case XPATH_NODESET:
4153 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004154 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004155 case XPATH_STRING:
4156 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4157 case XPATH_BOOLEAN:
4158 valuePush(ctxt, arg);
4159 xmlXPathBooleanFunction(ctxt, 1);
4160 valuePush(ctxt, val);
4161 return(xmlXPathCompareValues(ctxt, inf, strict));
4162 default:
4163 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004164 }
4165 return(0);
4166}
4167
4168/**
4169 * xmlXPathEqualNodeSetString
4170 * @arg: the nodeset object argument
4171 * @str: the string to compare to.
4172 *
4173 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4174 * If one object to be compared is a node-set and the other is a string,
4175 * then the comparison will be true if and only if there is a node in
4176 * the node-set such that the result of performing the comparison on the
4177 * string-value of the node and the other string is true.
4178 *
4179 * Returns 0 or 1 depending on the results of the test.
4180 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004181static int
Daniel Veillardf06307e2001-07-03 10:35:50 +00004182xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str)
4183{
Owen Taylor3473f882001-02-23 17:55:21 +00004184 int i;
4185 xmlNodeSetPtr ns;
4186 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004187 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004188
4189 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004190 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4191 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004192 ns = arg->nodesetval;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004193 hash = xmlXPathStringHash(str);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004194 if (ns == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004195 return (0);
Daniel Veillard73c9c042001-07-05 20:02:54 +00004196 if (ns->nodeNr <= 0) {
4197 if (hash == 0)
4198 return(1);
4199 return(0);
4200 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004201 for (i = 0; i < ns->nodeNr; i++) {
4202 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4203 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4204 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4205 xmlFree(str2);
4206 return (1);
4207 }
4208 if (str2 != NULL)
4209 xmlFree(str2);
4210 }
Owen Taylor3473f882001-02-23 17:55:21 +00004211 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004212 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004213}
4214
4215/**
4216 * xmlXPathEqualNodeSetFloat
4217 * @arg: the nodeset object argument
4218 * @f: the float to compare to
4219 *
4220 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4221 * If one object to be compared is a node-set and the other is a number,
4222 * then the comparison will be true if and only if there is a node in
4223 * the node-set such that the result of performing the comparison on the
4224 * number to be compared and on the result of converting the string-value
4225 * of that node to a number using the number function is true.
4226 *
4227 * Returns 0 or 1 depending on the results of the test.
4228 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004229static int
Owen Taylor3473f882001-02-23 17:55:21 +00004230xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, double f) {
4231 char buf[100] = "";
4232
4233 if ((arg == NULL) ||
4234 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4235 return(0);
4236
Bjorn Reesee1dc0112001-03-03 12:09:03 +00004237 xmlXPathFormatNumber(f, buf, sizeof(buf));
Owen Taylor3473f882001-02-23 17:55:21 +00004238 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
4239}
4240
4241
4242/**
4243 * xmlXPathEqualNodeSets
4244 * @arg1: first nodeset object argument
4245 * @arg2: second nodeset object argument
4246 *
4247 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
4248 * If both objects to be compared are node-sets, then the comparison
4249 * will be true if and only if there is a node in the first node-set and
4250 * a node in the second node-set such that the result of performing the
4251 * comparison on the string-values of the two nodes is true.
4252 *
4253 * (needless to say, this is a costly operation)
4254 *
4255 * Returns 0 or 1 depending on the results of the test.
4256 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004257static int
Owen Taylor3473f882001-02-23 17:55:21 +00004258xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4259 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004260 unsigned int *hashs1;
4261 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004262 xmlChar **values1;
4263 xmlChar **values2;
4264 int ret = 0;
4265 xmlNodeSetPtr ns1;
4266 xmlNodeSetPtr ns2;
4267
4268 if ((arg1 == NULL) ||
4269 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4270 return(0);
4271 if ((arg2 == NULL) ||
4272 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4273 return(0);
4274
4275 ns1 = arg1->nodesetval;
4276 ns2 = arg2->nodesetval;
4277
Daniel Veillard911f49a2001-04-07 15:39:35 +00004278 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004279 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004280 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004281 return(0);
4282
4283 /*
4284 * check if there is a node pertaining to both sets
4285 */
4286 for (i = 0;i < ns1->nodeNr;i++)
4287 for (j = 0;j < ns2->nodeNr;j++)
4288 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4289 return(1);
4290
4291 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
4292 if (values1 == NULL)
4293 return(0);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004294 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4295 if (hashs1 == NULL) {
4296 xmlFree(values1);
4297 return(0);
4298 }
Owen Taylor3473f882001-02-23 17:55:21 +00004299 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4300 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4301 if (values2 == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004302 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004303 xmlFree(values1);
4304 return(0);
4305 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004306 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4307 if (hashs2 == NULL) {
4308 xmlFree(hashs1);
4309 xmlFree(values1);
4310 xmlFree(values2);
4311 return(0);
4312 }
Owen Taylor3473f882001-02-23 17:55:21 +00004313 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4314 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004315 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004316 for (j = 0;j < ns2->nodeNr;j++) {
4317 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004318 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
4319 if (hashs1[i] == hashs2[j]) {
4320 if (values1[i] == NULL)
4321 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4322 if (values2[j] == NULL)
4323 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
4324 ret = xmlStrEqual(values1[i], values2[j]);
4325 if (ret)
4326 break;
4327 }
Owen Taylor3473f882001-02-23 17:55:21 +00004328 }
4329 if (ret)
4330 break;
4331 }
4332 for (i = 0;i < ns1->nodeNr;i++)
4333 if (values1[i] != NULL)
4334 xmlFree(values1[i]);
4335 for (j = 0;j < ns2->nodeNr;j++)
4336 if (values2[j] != NULL)
4337 xmlFree(values2[j]);
4338 xmlFree(values1);
4339 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004340 xmlFree(hashs1);
4341 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004342 return(ret);
4343}
4344
4345/**
4346 * xmlXPathEqualValues:
4347 * @ctxt: the XPath Parser context
4348 *
4349 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4350 *
4351 * Returns 0 or 1 depending on the results of the test.
4352 */
4353int
4354xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4355 xmlXPathObjectPtr arg1, arg2;
4356 int ret = 0;
4357
4358 arg1 = valuePop(ctxt);
4359 if (arg1 == NULL)
4360 XP_ERROR0(XPATH_INVALID_OPERAND);
4361
4362 arg2 = valuePop(ctxt);
4363 if (arg2 == NULL) {
4364 xmlXPathFreeObject(arg1);
4365 XP_ERROR0(XPATH_INVALID_OPERAND);
4366 }
4367
4368 if (arg1 == arg2) {
4369#ifdef DEBUG_EXPR
4370 xmlGenericError(xmlGenericErrorContext,
4371 "Equal: by pointer\n");
4372#endif
4373 return(1);
4374 }
4375
4376 switch (arg1->type) {
4377 case XPATH_UNDEFINED:
4378#ifdef DEBUG_EXPR
4379 xmlGenericError(xmlGenericErrorContext,
4380 "Equal: undefined\n");
4381#endif
4382 break;
4383 case XPATH_XSLT_TREE:
4384 case XPATH_NODESET:
4385 switch (arg2->type) {
4386 case XPATH_UNDEFINED:
4387#ifdef DEBUG_EXPR
4388 xmlGenericError(xmlGenericErrorContext,
4389 "Equal: undefined\n");
4390#endif
4391 break;
4392 case XPATH_XSLT_TREE:
4393 case XPATH_NODESET:
4394 ret = xmlXPathEqualNodeSets(arg1, arg2);
4395 break;
4396 case XPATH_BOOLEAN:
4397 if ((arg1->nodesetval == NULL) ||
4398 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4399 else
4400 ret = 1;
4401 ret = (ret == arg2->boolval);
4402 break;
4403 case XPATH_NUMBER:
4404 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
4405 break;
4406 case XPATH_STRING:
4407 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
4408 break;
4409 case XPATH_USERS:
4410 case XPATH_POINT:
4411 case XPATH_RANGE:
4412 case XPATH_LOCATIONSET:
4413 TODO
4414 break;
4415 }
4416 break;
4417 case XPATH_BOOLEAN:
4418 switch (arg2->type) {
4419 case XPATH_UNDEFINED:
4420#ifdef DEBUG_EXPR
4421 xmlGenericError(xmlGenericErrorContext,
4422 "Equal: undefined\n");
4423#endif
4424 break;
4425 case XPATH_NODESET:
4426 case XPATH_XSLT_TREE:
4427 if ((arg2->nodesetval == NULL) ||
Daniel Veillardbd6e6312002-04-01 08:04:14 +00004428 (arg2->nodesetval->nodeNr == 0))
4429 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004430 else
4431 ret = 1;
Daniel Veillardbd6e6312002-04-01 08:04:14 +00004432 ret = (ret == arg1->boolval);
Owen Taylor3473f882001-02-23 17:55:21 +00004433 break;
4434 case XPATH_BOOLEAN:
4435#ifdef DEBUG_EXPR
4436 xmlGenericError(xmlGenericErrorContext,
4437 "Equal: %d boolean %d \n",
4438 arg1->boolval, arg2->boolval);
4439#endif
4440 ret = (arg1->boolval == arg2->boolval);
4441 break;
4442 case XPATH_NUMBER:
4443 if (arg2->floatval) ret = 1;
4444 else ret = 0;
4445 ret = (arg1->boolval == ret);
4446 break;
4447 case XPATH_STRING:
4448 if ((arg2->stringval == NULL) ||
4449 (arg2->stringval[0] == 0)) ret = 0;
4450 else
4451 ret = 1;
4452 ret = (arg1->boolval == ret);
4453 break;
4454 case XPATH_USERS:
4455 case XPATH_POINT:
4456 case XPATH_RANGE:
4457 case XPATH_LOCATIONSET:
4458 TODO
4459 break;
4460 }
4461 break;
4462 case XPATH_NUMBER:
4463 switch (arg2->type) {
4464 case XPATH_UNDEFINED:
4465#ifdef DEBUG_EXPR
4466 xmlGenericError(xmlGenericErrorContext,
4467 "Equal: undefined\n");
4468#endif
4469 break;
4470 case XPATH_NODESET:
4471 case XPATH_XSLT_TREE:
4472 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
4473 break;
4474 case XPATH_BOOLEAN:
4475 if (arg1->floatval) ret = 1;
4476 else ret = 0;
4477 ret = (arg2->boolval == ret);
4478 break;
4479 case XPATH_STRING:
4480 valuePush(ctxt, arg2);
4481 xmlXPathNumberFunction(ctxt, 1);
4482 arg2 = valuePop(ctxt);
4483 /* no break on purpose */
4484 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004485 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004486 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4487 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004488 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4489 if (xmlXPathIsInf(arg2->floatval) == 1)
4490 ret = 1;
4491 else
4492 ret = 0;
4493 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4494 if (xmlXPathIsInf(arg2->floatval) == -1)
4495 ret = 1;
4496 else
4497 ret = 0;
4498 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4499 if (xmlXPathIsInf(arg1->floatval) == 1)
4500 ret = 1;
4501 else
4502 ret = 0;
4503 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4504 if (xmlXPathIsInf(arg1->floatval) == -1)
4505 ret = 1;
4506 else
4507 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004508 } else {
4509 ret = (arg1->floatval == arg2->floatval);
4510 }
Owen Taylor3473f882001-02-23 17:55:21 +00004511 break;
4512 case XPATH_USERS:
4513 case XPATH_POINT:
4514 case XPATH_RANGE:
4515 case XPATH_LOCATIONSET:
4516 TODO
4517 break;
4518 }
4519 break;
4520 case XPATH_STRING:
4521 switch (arg2->type) {
4522 case XPATH_UNDEFINED:
4523#ifdef DEBUG_EXPR
4524 xmlGenericError(xmlGenericErrorContext,
4525 "Equal: undefined\n");
4526#endif
4527 break;
4528 case XPATH_NODESET:
4529 case XPATH_XSLT_TREE:
4530 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
4531 break;
4532 case XPATH_BOOLEAN:
4533 if ((arg1->stringval == NULL) ||
4534 (arg1->stringval[0] == 0)) ret = 0;
4535 else
4536 ret = 1;
4537 ret = (arg2->boolval == ret);
4538 break;
4539 case XPATH_STRING:
4540 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4541 break;
4542 case XPATH_NUMBER:
4543 valuePush(ctxt, arg1);
4544 xmlXPathNumberFunction(ctxt, 1);
4545 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004546 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004547 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4548 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004549 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4550 if (xmlXPathIsInf(arg2->floatval) == 1)
4551 ret = 1;
4552 else
4553 ret = 0;
4554 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4555 if (xmlXPathIsInf(arg2->floatval) == -1)
4556 ret = 1;
4557 else
4558 ret = 0;
4559 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4560 if (xmlXPathIsInf(arg1->floatval) == 1)
4561 ret = 1;
4562 else
4563 ret = 0;
4564 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4565 if (xmlXPathIsInf(arg1->floatval) == -1)
4566 ret = 1;
4567 else
4568 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004569 } else {
4570 ret = (arg1->floatval == arg2->floatval);
4571 }
Owen Taylor3473f882001-02-23 17:55:21 +00004572 break;
4573 case XPATH_USERS:
4574 case XPATH_POINT:
4575 case XPATH_RANGE:
4576 case XPATH_LOCATIONSET:
4577 TODO
4578 break;
4579 }
4580 break;
4581 case XPATH_USERS:
4582 case XPATH_POINT:
4583 case XPATH_RANGE:
4584 case XPATH_LOCATIONSET:
4585 TODO
4586 break;
4587 }
4588 xmlXPathFreeObject(arg1);
4589 xmlXPathFreeObject(arg2);
4590 return(ret);
4591}
4592
4593
4594/**
4595 * xmlXPathCompareValues:
4596 * @ctxt: the XPath Parser context
4597 * @inf: less than (1) or greater than (0)
4598 * @strict: is the comparison strict
4599 *
4600 * Implement the compare operation on XPath objects:
4601 * @arg1 < @arg2 (1, 1, ...
4602 * @arg1 <= @arg2 (1, 0, ...
4603 * @arg1 > @arg2 (0, 1, ...
4604 * @arg1 >= @arg2 (0, 0, ...
4605 *
4606 * When neither object to be compared is a node-set and the operator is
4607 * <=, <, >=, >, then the objects are compared by converted both objects
4608 * to numbers and comparing the numbers according to IEEE 754. The <
4609 * comparison will be true if and only if the first number is less than the
4610 * second number. The <= comparison will be true if and only if the first
4611 * number is less than or equal to the second number. The > comparison
4612 * will be true if and only if the first number is greater than the second
4613 * number. The >= comparison will be true if and only if the first number
4614 * is greater than or equal to the second number.
4615 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004616 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00004617 */
4618int
4619xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004620 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004621 xmlXPathObjectPtr arg1, arg2;
4622
4623 arg2 = valuePop(ctxt);
4624 if (arg2 == NULL) {
4625 XP_ERROR0(XPATH_INVALID_OPERAND);
4626 }
4627
4628 arg1 = valuePop(ctxt);
4629 if (arg1 == NULL) {
4630 xmlXPathFreeObject(arg2);
4631 XP_ERROR0(XPATH_INVALID_OPERAND);
4632 }
4633
4634 if ((arg2->type == XPATH_NODESET) || (arg1->type == XPATH_NODESET)) {
4635 if ((arg2->type == XPATH_NODESET) && (arg1->type == XPATH_NODESET)) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004636 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004637 } else {
4638 if (arg1->type == XPATH_NODESET) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004639 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
4640 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004641 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004642 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
4643 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00004644 }
4645 }
4646 return(ret);
4647 }
4648
4649 if (arg1->type != XPATH_NUMBER) {
4650 valuePush(ctxt, arg1);
4651 xmlXPathNumberFunction(ctxt, 1);
4652 arg1 = valuePop(ctxt);
4653 }
4654 if (arg1->type != XPATH_NUMBER) {
4655 xmlXPathFreeObject(arg1);
4656 xmlXPathFreeObject(arg2);
4657 XP_ERROR0(XPATH_INVALID_OPERAND);
4658 }
4659 if (arg2->type != XPATH_NUMBER) {
4660 valuePush(ctxt, arg2);
4661 xmlXPathNumberFunction(ctxt, 1);
4662 arg2 = valuePop(ctxt);
4663 }
4664 if (arg2->type != XPATH_NUMBER) {
4665 xmlXPathFreeObject(arg1);
4666 xmlXPathFreeObject(arg2);
4667 XP_ERROR0(XPATH_INVALID_OPERAND);
4668 }
4669 /*
4670 * Add tests for infinity and nan
4671 * => feedback on 3.4 for Inf and NaN
4672 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004673 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00004674 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004675 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004676 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004677 arg1i=xmlXPathIsInf(arg1->floatval);
4678 arg2i=xmlXPathIsInf(arg2->floatval);
4679 if (inf && strict) {
4680 if ((arg1i == -1 && arg2i != -1) ||
4681 (arg2i == 1 && arg1i != 1)) {
4682 ret = 1;
4683 } else if (arg1i == 0 && arg2i == 0) {
4684 ret = (arg1->floatval < arg2->floatval);
4685 } else {
4686 ret = 0;
4687 }
4688 }
4689 else if (inf && !strict) {
4690 if (arg1i == -1 || arg2i == 1) {
4691 ret = 1;
4692 } else if (arg1i == 0 && arg2i == 0) {
4693 ret = (arg1->floatval <= arg2->floatval);
4694 } else {
4695 ret = 0;
4696 }
4697 }
4698 else if (!inf && strict) {
4699 if ((arg1i == 1 && arg2i != 1) ||
4700 (arg2i == -1 && arg1i != -1)) {
4701 ret = 1;
4702 } else if (arg1i == 0 && arg2i == 0) {
4703 ret = (arg1->floatval > arg2->floatval);
4704 } else {
4705 ret = 0;
4706 }
4707 }
4708 else if (!inf && !strict) {
4709 if (arg1i == 1 || arg2i == -1) {
4710 ret = 1;
4711 } else if (arg1i == 0 && arg2i == 0) {
4712 ret = (arg1->floatval >= arg2->floatval);
4713 } else {
4714 ret = 0;
4715 }
4716 }
Daniel Veillard21458c82002-03-27 16:12:22 +00004717 }
Owen Taylor3473f882001-02-23 17:55:21 +00004718 xmlXPathFreeObject(arg1);
4719 xmlXPathFreeObject(arg2);
4720 return(ret);
4721}
4722
4723/**
4724 * xmlXPathValueFlipSign:
4725 * @ctxt: the XPath Parser context
4726 *
4727 * Implement the unary - operation on an XPath object
4728 * The numeric operators convert their operands to numbers as if
4729 * by calling the number function.
4730 */
4731void
4732xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004733 CAST_TO_NUMBER;
4734 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00004735 if (ctxt->value->floatval == 0) {
4736 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
4737 ctxt->value->floatval = xmlXPathNZERO;
4738 else
4739 ctxt->value->floatval = 0;
4740 }
4741 else
4742 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00004743}
4744
4745/**
4746 * xmlXPathAddValues:
4747 * @ctxt: the XPath Parser context
4748 *
4749 * Implement the add operation on XPath objects:
4750 * The numeric operators convert their operands to numbers as if
4751 * by calling the number function.
4752 */
4753void
4754xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
4755 xmlXPathObjectPtr arg;
4756 double val;
4757
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004758 arg = valuePop(ctxt);
4759 if (arg == NULL)
4760 XP_ERROR(XPATH_INVALID_OPERAND);
4761 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004762 xmlXPathFreeObject(arg);
4763
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004764 CAST_TO_NUMBER;
4765 CHECK_TYPE(XPATH_NUMBER);
4766 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00004767}
4768
4769/**
4770 * xmlXPathSubValues:
4771 * @ctxt: the XPath Parser context
4772 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004773 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00004774 * The numeric operators convert their operands to numbers as if
4775 * by calling the number function.
4776 */
4777void
4778xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
4779 xmlXPathObjectPtr arg;
4780 double val;
4781
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004782 arg = valuePop(ctxt);
4783 if (arg == NULL)
4784 XP_ERROR(XPATH_INVALID_OPERAND);
4785 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004786 xmlXPathFreeObject(arg);
4787
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004788 CAST_TO_NUMBER;
4789 CHECK_TYPE(XPATH_NUMBER);
4790 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004791}
4792
4793/**
4794 * xmlXPathMultValues:
4795 * @ctxt: the XPath Parser context
4796 *
4797 * Implement the multiply operation on XPath objects:
4798 * The numeric operators convert their operands to numbers as if
4799 * by calling the number function.
4800 */
4801void
4802xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
4803 xmlXPathObjectPtr arg;
4804 double val;
4805
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004806 arg = valuePop(ctxt);
4807 if (arg == NULL)
4808 XP_ERROR(XPATH_INVALID_OPERAND);
4809 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004810 xmlXPathFreeObject(arg);
4811
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004812 CAST_TO_NUMBER;
4813 CHECK_TYPE(XPATH_NUMBER);
4814 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004815}
4816
4817/**
4818 * xmlXPathDivValues:
4819 * @ctxt: the XPath Parser context
4820 *
4821 * Implement the div operation on XPath objects @arg1 / @arg2:
4822 * The numeric operators convert their operands to numbers as if
4823 * by calling the number function.
4824 */
4825void
4826xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
4827 xmlXPathObjectPtr arg;
4828 double val;
4829
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004830 arg = valuePop(ctxt);
4831 if (arg == NULL)
4832 XP_ERROR(XPATH_INVALID_OPERAND);
4833 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004834 xmlXPathFreeObject(arg);
4835
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004836 CAST_TO_NUMBER;
4837 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004838 if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00004839 if (ctxt->value->floatval == 0)
4840 ctxt->value->floatval = xmlXPathNAN;
4841 else if (ctxt->value->floatval > 0)
4842 ctxt->value->floatval = xmlXPathNINF;
4843 else if (ctxt->value->floatval < 0)
4844 ctxt->value->floatval = xmlXPathPINF;
4845 }
4846 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00004847 if (ctxt->value->floatval == 0)
4848 ctxt->value->floatval = xmlXPathNAN;
4849 else if (ctxt->value->floatval > 0)
4850 ctxt->value->floatval = xmlXPathPINF;
4851 else if (ctxt->value->floatval < 0)
4852 ctxt->value->floatval = xmlXPathNINF;
4853 } else
4854 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004855}
4856
4857/**
4858 * xmlXPathModValues:
4859 * @ctxt: the XPath Parser context
4860 *
4861 * Implement the mod operation on XPath objects: @arg1 / @arg2
4862 * The numeric operators convert their operands to numbers as if
4863 * by calling the number function.
4864 */
4865void
4866xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
4867 xmlXPathObjectPtr arg;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00004868 double arg1, arg2, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00004869
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004870 arg = valuePop(ctxt);
4871 if (arg == NULL)
4872 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00004873 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004874 xmlXPathFreeObject(arg);
4875
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004876 CAST_TO_NUMBER;
4877 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00004878 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00004879 if (arg2 == 0)
4880 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00004881 else {
4882 tmp=arg1/arg2;
4883 ctxt->value->floatval = arg2 * (tmp - (double)((int)tmp));
4884 }
Owen Taylor3473f882001-02-23 17:55:21 +00004885}
4886
4887/************************************************************************
4888 * *
4889 * The traversal functions *
4890 * *
4891 ************************************************************************/
4892
Owen Taylor3473f882001-02-23 17:55:21 +00004893/*
4894 * A traversal function enumerates nodes along an axis.
4895 * Initially it must be called with NULL, and it indicates
4896 * termination on the axis by returning NULL.
4897 */
4898typedef xmlNodePtr (*xmlXPathTraversalFunction)
4899 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
4900
4901/**
4902 * xmlXPathNextSelf:
4903 * @ctxt: the XPath Parser context
4904 * @cur: the current node in the traversal
4905 *
4906 * Traversal function for the "self" direction
4907 * The self axis contains just the context node itself
4908 *
4909 * Returns the next element following that axis
4910 */
4911xmlNodePtr
4912xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4913 if (cur == NULL)
4914 return(ctxt->context->node);
4915 return(NULL);
4916}
4917
4918/**
4919 * xmlXPathNextChild:
4920 * @ctxt: the XPath Parser context
4921 * @cur: the current node in the traversal
4922 *
4923 * Traversal function for the "child" direction
4924 * The child axis contains the children of the context node in document order.
4925 *
4926 * Returns the next element following that axis
4927 */
4928xmlNodePtr
4929xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4930 if (cur == NULL) {
4931 if (ctxt->context->node == NULL) return(NULL);
4932 switch (ctxt->context->node->type) {
4933 case XML_ELEMENT_NODE:
4934 case XML_TEXT_NODE:
4935 case XML_CDATA_SECTION_NODE:
4936 case XML_ENTITY_REF_NODE:
4937 case XML_ENTITY_NODE:
4938 case XML_PI_NODE:
4939 case XML_COMMENT_NODE:
4940 case XML_NOTATION_NODE:
4941 case XML_DTD_NODE:
4942 return(ctxt->context->node->children);
4943 case XML_DOCUMENT_NODE:
4944 case XML_DOCUMENT_TYPE_NODE:
4945 case XML_DOCUMENT_FRAG_NODE:
4946 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004947#ifdef LIBXML_DOCB_ENABLED
4948 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004949#endif
4950 return(((xmlDocPtr) ctxt->context->node)->children);
4951 case XML_ELEMENT_DECL:
4952 case XML_ATTRIBUTE_DECL:
4953 case XML_ENTITY_DECL:
4954 case XML_ATTRIBUTE_NODE:
4955 case XML_NAMESPACE_DECL:
4956 case XML_XINCLUDE_START:
4957 case XML_XINCLUDE_END:
4958 return(NULL);
4959 }
4960 return(NULL);
4961 }
4962 if ((cur->type == XML_DOCUMENT_NODE) ||
4963 (cur->type == XML_HTML_DOCUMENT_NODE))
4964 return(NULL);
4965 return(cur->next);
4966}
4967
4968/**
4969 * xmlXPathNextDescendant:
4970 * @ctxt: the XPath Parser context
4971 * @cur: the current node in the traversal
4972 *
4973 * Traversal function for the "descendant" direction
4974 * the descendant axis contains the descendants of the context node in document
4975 * order; a descendant is a child or a child of a child and so on.
4976 *
4977 * Returns the next element following that axis
4978 */
4979xmlNodePtr
4980xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4981 if (cur == NULL) {
4982 if (ctxt->context->node == NULL)
4983 return(NULL);
4984 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4985 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4986 return(NULL);
4987
4988 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
4989 return(ctxt->context->doc->children);
4990 return(ctxt->context->node->children);
4991 }
4992
Daniel Veillard567e1b42001-08-01 15:53:47 +00004993 if (cur->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004994 if (cur->children->type != XML_ENTITY_DECL)
Daniel Veillard567e1b42001-08-01 15:53:47 +00004995 return(cur->children);
4996 }
4997
4998 if (cur == ctxt->context->node) return(NULL);
4999
Owen Taylor3473f882001-02-23 17:55:21 +00005000 if (cur->next != NULL) return(cur->next);
5001
5002 do {
5003 cur = cur->parent;
5004 if (cur == NULL) return(NULL);
5005 if (cur == ctxt->context->node) return(NULL);
5006 if (cur->next != NULL) {
5007 cur = cur->next;
5008 return(cur);
5009 }
5010 } while (cur != NULL);
5011 return(cur);
5012}
5013
5014/**
5015 * xmlXPathNextDescendantOrSelf:
5016 * @ctxt: the XPath Parser context
5017 * @cur: the current node in the traversal
5018 *
5019 * Traversal function for the "descendant-or-self" direction
5020 * the descendant-or-self axis contains the context node and the descendants
5021 * of the context node in document order; thus the context node is the first
5022 * node on the axis, and the first child of the context node is the second node
5023 * on the axis
5024 *
5025 * Returns the next element following that axis
5026 */
5027xmlNodePtr
5028xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5029 if (cur == NULL) {
5030 if (ctxt->context->node == NULL)
5031 return(NULL);
5032 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5033 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5034 return(NULL);
5035 return(ctxt->context->node);
5036 }
5037
5038 return(xmlXPathNextDescendant(ctxt, cur));
5039}
5040
5041/**
5042 * xmlXPathNextParent:
5043 * @ctxt: the XPath Parser context
5044 * @cur: the current node in the traversal
5045 *
5046 * Traversal function for the "parent" direction
5047 * The parent axis contains the parent of the context node, if there is one.
5048 *
5049 * Returns the next element following that axis
5050 */
5051xmlNodePtr
5052xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5053 /*
5054 * the parent of an attribute or namespace node is the element
5055 * to which the attribute or namespace node is attached
5056 * Namespace handling !!!
5057 */
5058 if (cur == NULL) {
5059 if (ctxt->context->node == NULL) return(NULL);
5060 switch (ctxt->context->node->type) {
5061 case XML_ELEMENT_NODE:
5062 case XML_TEXT_NODE:
5063 case XML_CDATA_SECTION_NODE:
5064 case XML_ENTITY_REF_NODE:
5065 case XML_ENTITY_NODE:
5066 case XML_PI_NODE:
5067 case XML_COMMENT_NODE:
5068 case XML_NOTATION_NODE:
5069 case XML_DTD_NODE:
5070 case XML_ELEMENT_DECL:
5071 case XML_ATTRIBUTE_DECL:
5072 case XML_XINCLUDE_START:
5073 case XML_XINCLUDE_END:
5074 case XML_ENTITY_DECL:
5075 if (ctxt->context->node->parent == NULL)
5076 return((xmlNodePtr) ctxt->context->doc);
5077 return(ctxt->context->node->parent);
5078 case XML_ATTRIBUTE_NODE: {
5079 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5080
5081 return(att->parent);
5082 }
5083 case XML_DOCUMENT_NODE:
5084 case XML_DOCUMENT_TYPE_NODE:
5085 case XML_DOCUMENT_FRAG_NODE:
5086 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005087#ifdef LIBXML_DOCB_ENABLED
5088 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005089#endif
5090 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005091 case XML_NAMESPACE_DECL: {
5092 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5093
5094 if ((ns->next != NULL) &&
5095 (ns->next->type != XML_NAMESPACE_DECL))
5096 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005097 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005098 }
Owen Taylor3473f882001-02-23 17:55:21 +00005099 }
5100 }
5101 return(NULL);
5102}
5103
5104/**
5105 * xmlXPathNextAncestor:
5106 * @ctxt: the XPath Parser context
5107 * @cur: the current node in the traversal
5108 *
5109 * Traversal function for the "ancestor" direction
5110 * the ancestor axis contains the ancestors of the context node; the ancestors
5111 * of the context node consist of the parent of context node and the parent's
5112 * parent and so on; the nodes are ordered in reverse document order; thus the
5113 * parent is the first node on the axis, and the parent's parent is the second
5114 * node on the axis
5115 *
5116 * Returns the next element following that axis
5117 */
5118xmlNodePtr
5119xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5120 /*
5121 * the parent of an attribute or namespace node is the element
5122 * to which the attribute or namespace node is attached
5123 * !!!!!!!!!!!!!
5124 */
5125 if (cur == NULL) {
5126 if (ctxt->context->node == NULL) return(NULL);
5127 switch (ctxt->context->node->type) {
5128 case XML_ELEMENT_NODE:
5129 case XML_TEXT_NODE:
5130 case XML_CDATA_SECTION_NODE:
5131 case XML_ENTITY_REF_NODE:
5132 case XML_ENTITY_NODE:
5133 case XML_PI_NODE:
5134 case XML_COMMENT_NODE:
5135 case XML_DTD_NODE:
5136 case XML_ELEMENT_DECL:
5137 case XML_ATTRIBUTE_DECL:
5138 case XML_ENTITY_DECL:
5139 case XML_NOTATION_NODE:
5140 case XML_XINCLUDE_START:
5141 case XML_XINCLUDE_END:
5142 if (ctxt->context->node->parent == NULL)
5143 return((xmlNodePtr) ctxt->context->doc);
5144 return(ctxt->context->node->parent);
5145 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005146 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005147
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005148 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005149 }
5150 case XML_DOCUMENT_NODE:
5151 case XML_DOCUMENT_TYPE_NODE:
5152 case XML_DOCUMENT_FRAG_NODE:
5153 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005154#ifdef LIBXML_DOCB_ENABLED
5155 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005156#endif
5157 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005158 case XML_NAMESPACE_DECL: {
5159 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5160
5161 if ((ns->next != NULL) &&
5162 (ns->next->type != XML_NAMESPACE_DECL))
5163 return((xmlNodePtr) ns->next);
5164 /* Bad, how did that namespace ended-up there ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005165 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005166 }
Owen Taylor3473f882001-02-23 17:55:21 +00005167 }
5168 return(NULL);
5169 }
5170 if (cur == ctxt->context->doc->children)
5171 return((xmlNodePtr) ctxt->context->doc);
5172 if (cur == (xmlNodePtr) ctxt->context->doc)
5173 return(NULL);
5174 switch (cur->type) {
5175 case XML_ELEMENT_NODE:
5176 case XML_TEXT_NODE:
5177 case XML_CDATA_SECTION_NODE:
5178 case XML_ENTITY_REF_NODE:
5179 case XML_ENTITY_NODE:
5180 case XML_PI_NODE:
5181 case XML_COMMENT_NODE:
5182 case XML_NOTATION_NODE:
5183 case XML_DTD_NODE:
5184 case XML_ELEMENT_DECL:
5185 case XML_ATTRIBUTE_DECL:
5186 case XML_ENTITY_DECL:
5187 case XML_XINCLUDE_START:
5188 case XML_XINCLUDE_END:
5189 return(cur->parent);
5190 case XML_ATTRIBUTE_NODE: {
5191 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5192
5193 return(att->parent);
5194 }
5195 case XML_DOCUMENT_NODE:
5196 case XML_DOCUMENT_TYPE_NODE:
5197 case XML_DOCUMENT_FRAG_NODE:
5198 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005199#ifdef LIBXML_DOCB_ENABLED
5200 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005201#endif
5202 return(NULL);
5203 case XML_NAMESPACE_DECL:
5204 /*
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005205 * this should not hapen a namespace can't be
5206 * the ancestor of another node
Owen Taylor3473f882001-02-23 17:55:21 +00005207 */
5208 return(NULL);
5209 }
5210 return(NULL);
5211}
5212
5213/**
5214 * xmlXPathNextAncestorOrSelf:
5215 * @ctxt: the XPath Parser context
5216 * @cur: the current node in the traversal
5217 *
5218 * Traversal function for the "ancestor-or-self" direction
5219 * he ancestor-or-self axis contains the context node and ancestors of
5220 * the context node in reverse document order; thus the context node is
5221 * the first node on the axis, and the context node's parent the second;
5222 * parent here is defined the same as with the parent axis.
5223 *
5224 * Returns the next element following that axis
5225 */
5226xmlNodePtr
5227xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5228 if (cur == NULL)
5229 return(ctxt->context->node);
5230 return(xmlXPathNextAncestor(ctxt, cur));
5231}
5232
5233/**
5234 * xmlXPathNextFollowingSibling:
5235 * @ctxt: the XPath Parser context
5236 * @cur: the current node in the traversal
5237 *
5238 * Traversal function for the "following-sibling" direction
5239 * The following-sibling axis contains the following siblings of the context
5240 * node in document order.
5241 *
5242 * Returns the next element following that axis
5243 */
5244xmlNodePtr
5245xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5246 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5247 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5248 return(NULL);
5249 if (cur == (xmlNodePtr) ctxt->context->doc)
5250 return(NULL);
5251 if (cur == NULL)
5252 return(ctxt->context->node->next);
5253 return(cur->next);
5254}
5255
5256/**
5257 * xmlXPathNextPrecedingSibling:
5258 * @ctxt: the XPath Parser context
5259 * @cur: the current node in the traversal
5260 *
5261 * Traversal function for the "preceding-sibling" direction
5262 * The preceding-sibling axis contains the preceding siblings of the context
5263 * node in reverse document order; the first preceding sibling is first on the
5264 * axis; the sibling preceding that node is the second on the axis and so on.
5265 *
5266 * Returns the next element following that axis
5267 */
5268xmlNodePtr
5269xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5270 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5271 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5272 return(NULL);
5273 if (cur == (xmlNodePtr) ctxt->context->doc)
5274 return(NULL);
5275 if (cur == NULL)
5276 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005277 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5278 cur = cur->prev;
5279 if (cur == NULL)
5280 return(ctxt->context->node->prev);
5281 }
Owen Taylor3473f882001-02-23 17:55:21 +00005282 return(cur->prev);
5283}
5284
5285/**
5286 * xmlXPathNextFollowing:
5287 * @ctxt: the XPath Parser context
5288 * @cur: the current node in the traversal
5289 *
5290 * Traversal function for the "following" direction
5291 * The following axis contains all nodes in the same document as the context
5292 * node that are after the context node in document order, excluding any
5293 * descendants and excluding attribute nodes and namespace nodes; the nodes
5294 * are ordered in document order
5295 *
5296 * Returns the next element following that axis
5297 */
5298xmlNodePtr
5299xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5300 if (cur != NULL && cur->children != NULL)
5301 return cur->children ;
5302 if (cur == NULL) cur = ctxt->context->node;
5303 if (cur == NULL) return(NULL) ; /* ERROR */
5304 if (cur->next != NULL) return(cur->next) ;
5305 do {
5306 cur = cur->parent;
5307 if (cur == NULL) return(NULL);
5308 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5309 if (cur->next != NULL) return(cur->next);
5310 } while (cur != NULL);
5311 return(cur);
5312}
5313
5314/*
5315 * xmlXPathIsAncestor:
5316 * @ancestor: the ancestor node
5317 * @node: the current node
5318 *
5319 * Check that @ancestor is a @node's ancestor
5320 *
5321 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5322 */
5323static int
5324xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5325 if ((ancestor == NULL) || (node == NULL)) return(0);
5326 /* nodes need to be in the same document */
5327 if (ancestor->doc != node->doc) return(0);
5328 /* avoid searching if ancestor or node is the root node */
5329 if (ancestor == (xmlNodePtr) node->doc) return(1);
5330 if (node == (xmlNodePtr) ancestor->doc) return(0);
5331 while (node->parent != NULL) {
5332 if (node->parent == ancestor)
5333 return(1);
5334 node = node->parent;
5335 }
5336 return(0);
5337}
5338
5339/**
5340 * xmlXPathNextPreceding:
5341 * @ctxt: the XPath Parser context
5342 * @cur: the current node in the traversal
5343 *
5344 * Traversal function for the "preceding" direction
5345 * the preceding axis contains all nodes in the same document as the context
5346 * node that are before the context node in document order, excluding any
5347 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5348 * ordered in reverse document order
5349 *
5350 * Returns the next element following that axis
5351 */
5352xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005353xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5354{
Owen Taylor3473f882001-02-23 17:55:21 +00005355 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005356 cur = ctxt->context->node;
5357 if (cur == NULL)
5358 return (NULL);
5359 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5360 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005361 do {
5362 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005363 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5364 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005365 }
5366
5367 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005368 if (cur == NULL)
5369 return (NULL);
5370 if (cur == ctxt->context->doc->children)
5371 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005372 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005373 return (cur);
5374}
5375
5376/**
5377 * xmlXPathNextPrecedingInternal:
5378 * @ctxt: the XPath Parser context
5379 * @cur: the current node in the traversal
5380 *
5381 * Traversal function for the "preceding" direction
5382 * the preceding axis contains all nodes in the same document as the context
5383 * node that are before the context node in document order, excluding any
5384 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5385 * ordered in reverse document order
5386 * This is a faster implementation but internal only since it requires a
5387 * state kept in the parser context: ctxt->ancestor.
5388 *
5389 * Returns the next element following that axis
5390 */
5391static xmlNodePtr
5392xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5393 xmlNodePtr cur)
5394{
5395 if (cur == NULL) {
5396 cur = ctxt->context->node;
5397 if (cur == NULL)
5398 return (NULL);
5399 ctxt->ancestor = cur->parent;
5400 }
5401 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5402 cur = cur->prev;
5403 while (cur->prev == NULL) {
5404 cur = cur->parent;
5405 if (cur == NULL)
5406 return (NULL);
5407 if (cur == ctxt->context->doc->children)
5408 return (NULL);
5409 if (cur != ctxt->ancestor)
5410 return (cur);
5411 ctxt->ancestor = cur->parent;
5412 }
5413 cur = cur->prev;
5414 while (cur->last != NULL)
5415 cur = cur->last;
5416 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005417}
5418
5419/**
5420 * xmlXPathNextNamespace:
5421 * @ctxt: the XPath Parser context
5422 * @cur: the current attribute in the traversal
5423 *
5424 * Traversal function for the "namespace" direction
5425 * the namespace axis contains the namespace nodes of the context node;
5426 * the order of nodes on this axis is implementation-defined; the axis will
5427 * be empty unless the context node is an element
5428 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005429 * We keep the XML namespace node at the end of the list.
5430 *
Owen Taylor3473f882001-02-23 17:55:21 +00005431 * Returns the next element following that axis
5432 */
5433xmlNodePtr
5434xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005435 xmlNodePtr ret;
5436
Owen Taylor3473f882001-02-23 17:55:21 +00005437 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005438 if (cur == (xmlNodePtr) xmlXPathXMLNamespace)
5439 return(NULL);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005440 if ((cur == NULL) || (ctxt->context->tmpNsList == NULL)) {
5441 if (ctxt->context->tmpNsList != NULL)
5442 xmlFree(ctxt->context->tmpNsList);
5443 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005444 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005445 if (ctxt->context->tmpNsList == NULL) return(NULL);
5446 ctxt->context->tmpNsNr = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005447 }
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005448 ret = (xmlNodePtr)ctxt->context->tmpNsList[ctxt->context->tmpNsNr++];
5449 if (ret == NULL) {
5450 xmlFree(ctxt->context->tmpNsList);
5451 ctxt->context->tmpNsList = NULL;
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005452 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005453 }
5454 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005455}
5456
5457/**
5458 * xmlXPathNextAttribute:
5459 * @ctxt: the XPath Parser context
5460 * @cur: the current attribute in the traversal
5461 *
5462 * Traversal function for the "attribute" direction
5463 * TODO: support DTD inherited default attributes
5464 *
5465 * Returns the next element following that axis
5466 */
5467xmlNodePtr
5468xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005469 if (ctxt->context->node == NULL)
5470 return(NULL);
5471 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5472 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005473 if (cur == NULL) {
5474 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5475 return(NULL);
5476 return((xmlNodePtr)ctxt->context->node->properties);
5477 }
5478 return((xmlNodePtr)cur->next);
5479}
5480
5481/************************************************************************
5482 * *
5483 * NodeTest Functions *
5484 * *
5485 ************************************************************************/
5486
Owen Taylor3473f882001-02-23 17:55:21 +00005487#define IS_FUNCTION 200
5488
Owen Taylor3473f882001-02-23 17:55:21 +00005489
5490/************************************************************************
5491 * *
5492 * Implicit tree core function library *
5493 * *
5494 ************************************************************************/
5495
5496/**
5497 * xmlXPathRoot:
5498 * @ctxt: the XPath Parser context
5499 *
5500 * Initialize the context to the root of the document
5501 */
5502void
5503xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5504 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5505 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5506}
5507
5508/************************************************************************
5509 * *
5510 * The explicit core function library *
5511 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5512 * *
5513 ************************************************************************/
5514
5515
5516/**
5517 * xmlXPathLastFunction:
5518 * @ctxt: the XPath Parser context
5519 * @nargs: the number of arguments
5520 *
5521 * Implement the last() XPath function
5522 * number last()
5523 * The last function returns the number of nodes in the context node list.
5524 */
5525void
5526xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5527 CHECK_ARITY(0);
5528 if (ctxt->context->contextSize >= 0) {
5529 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5530#ifdef DEBUG_EXPR
5531 xmlGenericError(xmlGenericErrorContext,
5532 "last() : %d\n", ctxt->context->contextSize);
5533#endif
5534 } else {
5535 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5536 }
5537}
5538
5539/**
5540 * xmlXPathPositionFunction:
5541 * @ctxt: the XPath Parser context
5542 * @nargs: the number of arguments
5543 *
5544 * Implement the position() XPath function
5545 * number position()
5546 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005547 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00005548 * will be equal to last().
5549 */
5550void
5551xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5552 CHECK_ARITY(0);
5553 if (ctxt->context->proximityPosition >= 0) {
5554 valuePush(ctxt,
5555 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5556#ifdef DEBUG_EXPR
5557 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5558 ctxt->context->proximityPosition);
5559#endif
5560 } else {
5561 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5562 }
5563}
5564
5565/**
5566 * xmlXPathCountFunction:
5567 * @ctxt: the XPath Parser context
5568 * @nargs: the number of arguments
5569 *
5570 * Implement the count() XPath function
5571 * number count(node-set)
5572 */
5573void
5574xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5575 xmlXPathObjectPtr cur;
5576
5577 CHECK_ARITY(1);
5578 if ((ctxt->value == NULL) ||
5579 ((ctxt->value->type != XPATH_NODESET) &&
5580 (ctxt->value->type != XPATH_XSLT_TREE)))
5581 XP_ERROR(XPATH_INVALID_TYPE);
5582 cur = valuePop(ctxt);
5583
Daniel Veillard911f49a2001-04-07 15:39:35 +00005584 if ((cur == NULL) || (cur->nodesetval == NULL))
5585 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00005586 else if (cur->type == XPATH_NODESET) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00005587 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00005588 } else {
5589 if ((cur->nodesetval->nodeNr != 1) ||
5590 (cur->nodesetval->nodeTab == NULL)) {
5591 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5592 } else {
5593 xmlNodePtr tmp;
5594 int i = 0;
5595
5596 tmp = cur->nodesetval->nodeTab[0];
5597 if (tmp != NULL) {
5598 tmp = tmp->children;
5599 while (tmp != NULL) {
5600 tmp = tmp->next;
5601 i++;
5602 }
5603 }
5604 valuePush(ctxt, xmlXPathNewFloat((double) i));
5605 }
5606 }
Owen Taylor3473f882001-02-23 17:55:21 +00005607 xmlXPathFreeObject(cur);
5608}
5609
5610/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005611 * xmlXPathGetElementsByIds:
5612 * @doc: the document
5613 * @ids: a whitespace separated list of IDs
5614 *
5615 * Selects elements by their unique ID.
5616 *
5617 * Returns a node-set of selected elements.
5618 */
5619static xmlNodeSetPtr
5620xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5621 xmlNodeSetPtr ret;
5622 const xmlChar *cur = ids;
5623 xmlChar *ID;
5624 xmlAttrPtr attr;
5625 xmlNodePtr elem = NULL;
5626
5627 ret = xmlXPathNodeSetCreate(NULL);
5628
5629 while (IS_BLANK(*cur)) cur++;
5630 while (*cur != 0) {
5631 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
5632 (*cur == '.') || (*cur == '-') ||
5633 (*cur == '_') || (*cur == ':') ||
5634 (IS_COMBINING(*cur)) ||
5635 (IS_EXTENDER(*cur)))
5636 cur++;
5637
5638 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
5639
5640 ID = xmlStrndup(ids, cur - ids);
5641 attr = xmlGetID(doc, ID);
5642 if (attr != NULL) {
5643 elem = attr->parent;
5644 xmlXPathNodeSetAdd(ret, elem);
5645 }
5646 if (ID != NULL)
5647 xmlFree(ID);
5648
5649 while (IS_BLANK(*cur)) cur++;
5650 ids = cur;
5651 }
5652 return(ret);
5653}
5654
5655/**
Owen Taylor3473f882001-02-23 17:55:21 +00005656 * xmlXPathIdFunction:
5657 * @ctxt: the XPath Parser context
5658 * @nargs: the number of arguments
5659 *
5660 * Implement the id() XPath function
5661 * node-set id(object)
5662 * The id function selects elements by their unique ID
5663 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
5664 * then the result is the union of the result of applying id to the
5665 * string value of each of the nodes in the argument node-set. When the
5666 * argument to id is of any other type, the argument is converted to a
5667 * string as if by a call to the string function; the string is split
5668 * into a whitespace-separated list of tokens (whitespace is any sequence
5669 * of characters matching the production S); the result is a node-set
5670 * containing the elements in the same document as the context node that
5671 * have a unique ID equal to any of the tokens in the list.
5672 */
5673void
5674xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005675 xmlChar *tokens;
5676 xmlNodeSetPtr ret;
5677 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00005678
5679 CHECK_ARITY(1);
5680 obj = valuePop(ctxt);
5681 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
5682 if (obj->type == XPATH_NODESET) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005683 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00005684 int i;
5685
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005686 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005687
Daniel Veillard911f49a2001-04-07 15:39:35 +00005688 if (obj->nodesetval != NULL) {
5689 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005690 tokens =
5691 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
5692 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
5693 ret = xmlXPathNodeSetMerge(ret, ns);
5694 xmlXPathFreeNodeSet(ns);
5695 if (tokens != NULL)
5696 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00005697 }
Owen Taylor3473f882001-02-23 17:55:21 +00005698 }
5699
5700 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005701 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005702 return;
5703 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005704 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00005705
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005706 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
5707 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005708
Owen Taylor3473f882001-02-23 17:55:21 +00005709 xmlXPathFreeObject(obj);
5710 return;
5711}
5712
5713/**
5714 * xmlXPathLocalNameFunction:
5715 * @ctxt: the XPath Parser context
5716 * @nargs: the number of arguments
5717 *
5718 * Implement the local-name() XPath function
5719 * string local-name(node-set?)
5720 * The local-name function returns a string containing the local part
5721 * of the name of the node in the argument node-set that is first in
5722 * document order. If the node-set is empty or the first node has no
5723 * name, an empty string is returned. If the argument is omitted it
5724 * defaults to the context node.
5725 */
5726void
5727xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5728 xmlXPathObjectPtr cur;
5729
5730 if (nargs == 0) {
5731 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5732 nargs = 1;
5733 }
5734
5735 CHECK_ARITY(1);
5736 if ((ctxt->value == NULL) ||
5737 ((ctxt->value->type != XPATH_NODESET) &&
5738 (ctxt->value->type != XPATH_XSLT_TREE)))
5739 XP_ERROR(XPATH_INVALID_TYPE);
5740 cur = valuePop(ctxt);
5741
Daniel Veillard911f49a2001-04-07 15:39:35 +00005742 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005743 valuePush(ctxt, xmlXPathNewCString(""));
5744 } else {
5745 int i = 0; /* Should be first in document order !!!!! */
5746 switch (cur->nodesetval->nodeTab[i]->type) {
5747 case XML_ELEMENT_NODE:
5748 case XML_ATTRIBUTE_NODE:
5749 case XML_PI_NODE:
5750 valuePush(ctxt,
5751 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
5752 break;
5753 case XML_NAMESPACE_DECL:
5754 valuePush(ctxt, xmlXPathNewString(
5755 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
5756 break;
5757 default:
5758 valuePush(ctxt, xmlXPathNewCString(""));
5759 }
5760 }
5761 xmlXPathFreeObject(cur);
5762}
5763
5764/**
5765 * xmlXPathNamespaceURIFunction:
5766 * @ctxt: the XPath Parser context
5767 * @nargs: the number of arguments
5768 *
5769 * Implement the namespace-uri() XPath function
5770 * string namespace-uri(node-set?)
5771 * The namespace-uri function returns a string containing the
5772 * namespace URI of the expanded name of the node in the argument
5773 * node-set that is first in document order. If the node-set is empty,
5774 * the first node has no name, or the expanded name has no namespace
5775 * URI, an empty string is returned. If the argument is omitted it
5776 * defaults to the context node.
5777 */
5778void
5779xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5780 xmlXPathObjectPtr cur;
5781
5782 if (nargs == 0) {
5783 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5784 nargs = 1;
5785 }
5786 CHECK_ARITY(1);
5787 if ((ctxt->value == NULL) ||
5788 ((ctxt->value->type != XPATH_NODESET) &&
5789 (ctxt->value->type != XPATH_XSLT_TREE)))
5790 XP_ERROR(XPATH_INVALID_TYPE);
5791 cur = valuePop(ctxt);
5792
Daniel Veillard911f49a2001-04-07 15:39:35 +00005793 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005794 valuePush(ctxt, xmlXPathNewCString(""));
5795 } else {
5796 int i = 0; /* Should be first in document order !!!!! */
5797 switch (cur->nodesetval->nodeTab[i]->type) {
5798 case XML_ELEMENT_NODE:
5799 case XML_ATTRIBUTE_NODE:
5800 if (cur->nodesetval->nodeTab[i]->ns == NULL)
5801 valuePush(ctxt, xmlXPathNewCString(""));
5802 else
5803 valuePush(ctxt, xmlXPathNewString(
5804 cur->nodesetval->nodeTab[i]->ns->href));
5805 break;
5806 default:
5807 valuePush(ctxt, xmlXPathNewCString(""));
5808 }
5809 }
5810 xmlXPathFreeObject(cur);
5811}
5812
5813/**
5814 * xmlXPathNameFunction:
5815 * @ctxt: the XPath Parser context
5816 * @nargs: the number of arguments
5817 *
5818 * Implement the name() XPath function
5819 * string name(node-set?)
5820 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005821 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00005822 * order. The QName must represent the name with respect to the namespace
5823 * declarations in effect on the node whose name is being represented.
5824 * Typically, this will be the form in which the name occurred in the XML
5825 * source. This need not be the case if there are namespace declarations
5826 * in effect on the node that associate multiple prefixes with the same
5827 * namespace. However, an implementation may include information about
5828 * the original prefix in its representation of nodes; in this case, an
5829 * implementation can ensure that the returned string is always the same
5830 * as the QName used in the XML source. If the argument it omitted it
5831 * defaults to the context node.
5832 * Libxml keep the original prefix so the "real qualified name" used is
5833 * returned.
5834 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005835static void
Daniel Veillard04383752001-07-08 14:27:15 +00005836xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
5837{
Owen Taylor3473f882001-02-23 17:55:21 +00005838 xmlXPathObjectPtr cur;
5839
5840 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00005841 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5842 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00005843 }
5844
5845 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00005846 if ((ctxt->value == NULL) ||
5847 ((ctxt->value->type != XPATH_NODESET) &&
5848 (ctxt->value->type != XPATH_XSLT_TREE)))
5849 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00005850 cur = valuePop(ctxt);
5851
Daniel Veillard911f49a2001-04-07 15:39:35 +00005852 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00005853 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00005854 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00005855 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005856
Daniel Veillard04383752001-07-08 14:27:15 +00005857 switch (cur->nodesetval->nodeTab[i]->type) {
5858 case XML_ELEMENT_NODE:
5859 case XML_ATTRIBUTE_NODE:
5860 if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
5861 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL))
5862 valuePush(ctxt,
5863 xmlXPathNewString(cur->nodesetval->
5864 nodeTab[i]->name));
5865
5866 else {
5867 char name[2000];
5868
5869 snprintf(name, sizeof(name), "%s:%s",
5870 (char *) cur->nodesetval->nodeTab[i]->ns->
5871 prefix,
5872 (char *) cur->nodesetval->nodeTab[i]->name);
5873 name[sizeof(name) - 1] = 0;
5874 valuePush(ctxt, xmlXPathNewCString(name));
5875 }
5876 break;
5877 default:
5878 valuePush(ctxt,
5879 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
5880 xmlXPathLocalNameFunction(ctxt, 1);
5881 }
Owen Taylor3473f882001-02-23 17:55:21 +00005882 }
5883 xmlXPathFreeObject(cur);
5884}
5885
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005886
5887/**
Owen Taylor3473f882001-02-23 17:55:21 +00005888 * xmlXPathStringFunction:
5889 * @ctxt: the XPath Parser context
5890 * @nargs: the number of arguments
5891 *
5892 * Implement the string() XPath function
5893 * string string(object?)
5894 * he string function converts an object to a string as follows:
5895 * - A node-set is converted to a string by returning the value of
5896 * the node in the node-set that is first in document order.
5897 * If the node-set is empty, an empty string is returned.
5898 * - A number is converted to a string as follows
5899 * + NaN is converted to the string NaN
5900 * + positive zero is converted to the string 0
5901 * + negative zero is converted to the string 0
5902 * + positive infinity is converted to the string Infinity
5903 * + negative infinity is converted to the string -Infinity
5904 * + if the number is an integer, the number is represented in
5905 * decimal form as a Number with no decimal point and no leading
5906 * zeros, preceded by a minus sign (-) if the number is negative
5907 * + otherwise, the number is represented in decimal form as a
5908 * Number including a decimal point with at least one digit
5909 * before the decimal point and at least one digit after the
5910 * decimal point, preceded by a minus sign (-) if the number
5911 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005912 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00005913 * before the decimal point; beyond the one required digit
5914 * after the decimal point there must be as many, but only as
5915 * many, more digits as are needed to uniquely distinguish the
5916 * number from all other IEEE 754 numeric values.
5917 * - The boolean false value is converted to the string false.
5918 * The boolean true value is converted to the string true.
5919 *
5920 * If the argument is omitted, it defaults to a node-set with the
5921 * context node as its only member.
5922 */
5923void
5924xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5925 xmlXPathObjectPtr cur;
5926
5927 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005928 valuePush(ctxt,
5929 xmlXPathWrapString(
5930 xmlXPathCastNodeToString(ctxt->context->node)));
5931 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005932 }
5933
5934 CHECK_ARITY(1);
5935 cur = valuePop(ctxt);
5936 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005937 cur = xmlXPathConvertString(cur);
5938 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005939}
5940
5941/**
5942 * xmlXPathStringLengthFunction:
5943 * @ctxt: the XPath Parser context
5944 * @nargs: the number of arguments
5945 *
5946 * Implement the string-length() XPath function
5947 * number string-length(string?)
5948 * The string-length returns the number of characters in the string
5949 * (see [3.6 Strings]). If the argument is omitted, it defaults to
5950 * the context node converted to a string, in other words the value
5951 * of the context node.
5952 */
5953void
5954xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5955 xmlXPathObjectPtr cur;
5956
5957 if (nargs == 0) {
5958 if (ctxt->context->node == NULL) {
5959 valuePush(ctxt, xmlXPathNewFloat(0));
5960 } else {
5961 xmlChar *content;
5962
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005963 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00005964 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00005965 xmlFree(content);
5966 }
5967 return;
5968 }
5969 CHECK_ARITY(1);
5970 CAST_TO_STRING;
5971 CHECK_TYPE(XPATH_STRING);
5972 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00005973 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00005974 xmlXPathFreeObject(cur);
5975}
5976
5977/**
5978 * xmlXPathConcatFunction:
5979 * @ctxt: the XPath Parser context
5980 * @nargs: the number of arguments
5981 *
5982 * Implement the concat() XPath function
5983 * string concat(string, string, string*)
5984 * The concat function returns the concatenation of its arguments.
5985 */
5986void
5987xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5988 xmlXPathObjectPtr cur, newobj;
5989 xmlChar *tmp;
5990
5991 if (nargs < 2) {
5992 CHECK_ARITY(2);
5993 }
5994
5995 CAST_TO_STRING;
5996 cur = valuePop(ctxt);
5997 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
5998 xmlXPathFreeObject(cur);
5999 return;
6000 }
6001 nargs--;
6002
6003 while (nargs > 0) {
6004 CAST_TO_STRING;
6005 newobj = valuePop(ctxt);
6006 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6007 xmlXPathFreeObject(newobj);
6008 xmlXPathFreeObject(cur);
6009 XP_ERROR(XPATH_INVALID_TYPE);
6010 }
6011 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6012 newobj->stringval = cur->stringval;
6013 cur->stringval = tmp;
6014
6015 xmlXPathFreeObject(newobj);
6016 nargs--;
6017 }
6018 valuePush(ctxt, cur);
6019}
6020
6021/**
6022 * xmlXPathContainsFunction:
6023 * @ctxt: the XPath Parser context
6024 * @nargs: the number of arguments
6025 *
6026 * Implement the contains() XPath function
6027 * boolean contains(string, string)
6028 * The contains function returns true if the first argument string
6029 * contains the second argument string, and otherwise returns false.
6030 */
6031void
6032xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6033 xmlXPathObjectPtr hay, needle;
6034
6035 CHECK_ARITY(2);
6036 CAST_TO_STRING;
6037 CHECK_TYPE(XPATH_STRING);
6038 needle = valuePop(ctxt);
6039 CAST_TO_STRING;
6040 hay = valuePop(ctxt);
6041 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6042 xmlXPathFreeObject(hay);
6043 xmlXPathFreeObject(needle);
6044 XP_ERROR(XPATH_INVALID_TYPE);
6045 }
6046 if (xmlStrstr(hay->stringval, needle->stringval))
6047 valuePush(ctxt, xmlXPathNewBoolean(1));
6048 else
6049 valuePush(ctxt, xmlXPathNewBoolean(0));
6050 xmlXPathFreeObject(hay);
6051 xmlXPathFreeObject(needle);
6052}
6053
6054/**
6055 * xmlXPathStartsWithFunction:
6056 * @ctxt: the XPath Parser context
6057 * @nargs: the number of arguments
6058 *
6059 * Implement the starts-with() XPath function
6060 * boolean starts-with(string, string)
6061 * The starts-with function returns true if the first argument string
6062 * starts with the second argument string, and otherwise returns false.
6063 */
6064void
6065xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6066 xmlXPathObjectPtr hay, needle;
6067 int n;
6068
6069 CHECK_ARITY(2);
6070 CAST_TO_STRING;
6071 CHECK_TYPE(XPATH_STRING);
6072 needle = valuePop(ctxt);
6073 CAST_TO_STRING;
6074 hay = valuePop(ctxt);
6075 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6076 xmlXPathFreeObject(hay);
6077 xmlXPathFreeObject(needle);
6078 XP_ERROR(XPATH_INVALID_TYPE);
6079 }
6080 n = xmlStrlen(needle->stringval);
6081 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6082 valuePush(ctxt, xmlXPathNewBoolean(0));
6083 else
6084 valuePush(ctxt, xmlXPathNewBoolean(1));
6085 xmlXPathFreeObject(hay);
6086 xmlXPathFreeObject(needle);
6087}
6088
6089/**
6090 * xmlXPathSubstringFunction:
6091 * @ctxt: the XPath Parser context
6092 * @nargs: the number of arguments
6093 *
6094 * Implement the substring() XPath function
6095 * string substring(string, number, number?)
6096 * The substring function returns the substring of the first argument
6097 * starting at the position specified in the second argument with
6098 * length specified in the third argument. For example,
6099 * substring("12345",2,3) returns "234". If the third argument is not
6100 * specified, it returns the substring starting at the position specified
6101 * in the second argument and continuing to the end of the string. For
6102 * example, substring("12345",2) returns "2345". More precisely, each
6103 * character in the string (see [3.6 Strings]) is considered to have a
6104 * numeric position: the position of the first character is 1, the position
6105 * of the second character is 2 and so on. The returned substring contains
6106 * those characters for which the position of the character is greater than
6107 * or equal to the second argument and, if the third argument is specified,
6108 * less than the sum of the second and third arguments; the comparisons
6109 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6110 * - substring("12345", 1.5, 2.6) returns "234"
6111 * - substring("12345", 0, 3) returns "12"
6112 * - substring("12345", 0 div 0, 3) returns ""
6113 * - substring("12345", 1, 0 div 0) returns ""
6114 * - substring("12345", -42, 1 div 0) returns "12345"
6115 * - substring("12345", -1 div 0, 1 div 0) returns ""
6116 */
6117void
6118xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6119 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006120 double le=0, in;
6121 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006122 xmlChar *ret;
6123
Owen Taylor3473f882001-02-23 17:55:21 +00006124 if (nargs < 2) {
6125 CHECK_ARITY(2);
6126 }
6127 if (nargs > 3) {
6128 CHECK_ARITY(3);
6129 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006130 /*
6131 * take care of possible last (position) argument
6132 */
Owen Taylor3473f882001-02-23 17:55:21 +00006133 if (nargs == 3) {
6134 CAST_TO_NUMBER;
6135 CHECK_TYPE(XPATH_NUMBER);
6136 len = valuePop(ctxt);
6137 le = len->floatval;
6138 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006139 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006140
Owen Taylor3473f882001-02-23 17:55:21 +00006141 CAST_TO_NUMBER;
6142 CHECK_TYPE(XPATH_NUMBER);
6143 start = valuePop(ctxt);
6144 in = start->floatval;
6145 xmlXPathFreeObject(start);
6146 CAST_TO_STRING;
6147 CHECK_TYPE(XPATH_STRING);
6148 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006149 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006150
Daniel Veillard97ac1312001-05-30 19:14:17 +00006151 /*
6152 * If last pos not present, calculate last position
6153 */
6154 if (nargs != 3)
6155 le = m;
6156
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006157 /* Need to check for the special cases where either
6158 * the index is NaN, the length is NaN, or both
6159 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00006160 */
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006161 if (!xmlXPathIsNaN(in + le)) {
6162 /*
6163 * To meet our requirements, initial index calculations
6164 * must be done before we convert to integer format
6165 *
6166 * First we normalize indices
6167 */
6168 in -= 1.0;
6169 le += in;
6170 if (in < 0.0)
6171 in = 0.0;
6172 if (le > (double)m)
6173 le = (double)m;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006174
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006175 /*
6176 * Now we go to integer form, rounding up
6177 */
6178 i = (int) in;
6179 if (((double)i) != in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00006180
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006181 l = (int) le;
6182 if (((double)l) != le) l++;
Owen Taylor3473f882001-02-23 17:55:21 +00006183
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006184 if (l > m) l=m;
Owen Taylor3473f882001-02-23 17:55:21 +00006185
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006186 /* number of chars to copy */
6187 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00006188
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006189 ret = xmlUTF8Strsub(str->stringval, i, l);
6190 }
6191 else {
6192 ret = NULL;
6193 }
6194
Owen Taylor3473f882001-02-23 17:55:21 +00006195 if (ret == NULL)
6196 valuePush(ctxt, xmlXPathNewCString(""));
6197 else {
6198 valuePush(ctxt, xmlXPathNewString(ret));
6199 xmlFree(ret);
6200 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006201
Owen Taylor3473f882001-02-23 17:55:21 +00006202 xmlXPathFreeObject(str);
6203}
6204
6205/**
6206 * xmlXPathSubstringBeforeFunction:
6207 * @ctxt: the XPath Parser context
6208 * @nargs: the number of arguments
6209 *
6210 * Implement the substring-before() XPath function
6211 * string substring-before(string, string)
6212 * The substring-before function returns the substring of the first
6213 * argument string that precedes the first occurrence of the second
6214 * argument string in the first argument string, or the empty string
6215 * if the first argument string does not contain the second argument
6216 * string. For example, substring-before("1999/04/01","/") returns 1999.
6217 */
6218void
6219xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6220 xmlXPathObjectPtr str;
6221 xmlXPathObjectPtr find;
6222 xmlBufferPtr target;
6223 const xmlChar *point;
6224 int offset;
6225
6226 CHECK_ARITY(2);
6227 CAST_TO_STRING;
6228 find = valuePop(ctxt);
6229 CAST_TO_STRING;
6230 str = valuePop(ctxt);
6231
6232 target = xmlBufferCreate();
6233 if (target) {
6234 point = xmlStrstr(str->stringval, find->stringval);
6235 if (point) {
6236 offset = (int)(point - str->stringval);
6237 xmlBufferAdd(target, str->stringval, offset);
6238 }
6239 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6240 xmlBufferFree(target);
6241 }
6242
6243 xmlXPathFreeObject(str);
6244 xmlXPathFreeObject(find);
6245}
6246
6247/**
6248 * xmlXPathSubstringAfterFunction:
6249 * @ctxt: the XPath Parser context
6250 * @nargs: the number of arguments
6251 *
6252 * Implement the substring-after() XPath function
6253 * string substring-after(string, string)
6254 * The substring-after function returns the substring of the first
6255 * argument string that follows the first occurrence of the second
6256 * argument string in the first argument string, or the empty stringi
6257 * if the first argument string does not contain the second argument
6258 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6259 * and substring-after("1999/04/01","19") returns 99/04/01.
6260 */
6261void
6262xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6263 xmlXPathObjectPtr str;
6264 xmlXPathObjectPtr find;
6265 xmlBufferPtr target;
6266 const xmlChar *point;
6267 int offset;
6268
6269 CHECK_ARITY(2);
6270 CAST_TO_STRING;
6271 find = valuePop(ctxt);
6272 CAST_TO_STRING;
6273 str = valuePop(ctxt);
6274
6275 target = xmlBufferCreate();
6276 if (target) {
6277 point = xmlStrstr(str->stringval, find->stringval);
6278 if (point) {
6279 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6280 xmlBufferAdd(target, &str->stringval[offset],
6281 xmlStrlen(str->stringval) - offset);
6282 }
6283 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6284 xmlBufferFree(target);
6285 }
6286
6287 xmlXPathFreeObject(str);
6288 xmlXPathFreeObject(find);
6289}
6290
6291/**
6292 * xmlXPathNormalizeFunction:
6293 * @ctxt: the XPath Parser context
6294 * @nargs: the number of arguments
6295 *
6296 * Implement the normalize-space() XPath function
6297 * string normalize-space(string?)
6298 * The normalize-space function returns the argument string with white
6299 * space normalized by stripping leading and trailing whitespace
6300 * and replacing sequences of whitespace characters by a single
6301 * space. Whitespace characters are the same allowed by the S production
6302 * in XML. If the argument is omitted, it defaults to the context
6303 * node converted to a string, in other words the value of the context node.
6304 */
6305void
6306xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6307 xmlXPathObjectPtr obj = NULL;
6308 xmlChar *source = NULL;
6309 xmlBufferPtr target;
6310 xmlChar blank;
6311
6312 if (nargs == 0) {
6313 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006314 valuePush(ctxt,
6315 xmlXPathWrapString(
6316 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006317 nargs = 1;
6318 }
6319
6320 CHECK_ARITY(1);
6321 CAST_TO_STRING;
6322 CHECK_TYPE(XPATH_STRING);
6323 obj = valuePop(ctxt);
6324 source = obj->stringval;
6325
6326 target = xmlBufferCreate();
6327 if (target && source) {
6328
6329 /* Skip leading whitespaces */
6330 while (IS_BLANK(*source))
6331 source++;
6332
6333 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6334 blank = 0;
6335 while (*source) {
6336 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006337 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006338 } else {
6339 if (blank) {
6340 xmlBufferAdd(target, &blank, 1);
6341 blank = 0;
6342 }
6343 xmlBufferAdd(target, source, 1);
6344 }
6345 source++;
6346 }
6347
6348 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6349 xmlBufferFree(target);
6350 }
6351 xmlXPathFreeObject(obj);
6352}
6353
6354/**
6355 * xmlXPathTranslateFunction:
6356 * @ctxt: the XPath Parser context
6357 * @nargs: the number of arguments
6358 *
6359 * Implement the translate() XPath function
6360 * string translate(string, string, string)
6361 * The translate function returns the first argument string with
6362 * occurrences of characters in the second argument string replaced
6363 * by the character at the corresponding position in the third argument
6364 * string. For example, translate("bar","abc","ABC") returns the string
6365 * BAr. If there is a character in the second argument string with no
6366 * character at a corresponding position in the third argument string
6367 * (because the second argument string is longer than the third argument
6368 * string), then occurrences of that character in the first argument
6369 * string are removed. For example, translate("--aaa--","abc-","ABC")
6370 * returns "AAA". If a character occurs more than once in second
6371 * argument string, then the first occurrence determines the replacement
6372 * character. If the third argument string is longer than the second
6373 * argument string, then excess characters are ignored.
6374 */
6375void
6376xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006377 xmlXPathObjectPtr str;
6378 xmlXPathObjectPtr from;
6379 xmlXPathObjectPtr to;
6380 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006381 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006382 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006383 xmlChar *point;
6384 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006385
Daniel Veillarde043ee12001-04-16 14:08:07 +00006386 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006387
Daniel Veillarde043ee12001-04-16 14:08:07 +00006388 CAST_TO_STRING;
6389 to = valuePop(ctxt);
6390 CAST_TO_STRING;
6391 from = valuePop(ctxt);
6392 CAST_TO_STRING;
6393 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006394
Daniel Veillarde043ee12001-04-16 14:08:07 +00006395 target = xmlBufferCreate();
6396 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006397 max = xmlUTF8Strlen(to->stringval);
6398 for (cptr = str->stringval; (ch=*cptr); ) {
6399 offset = xmlUTF8Strloc(from->stringval, cptr);
6400 if (offset >= 0) {
6401 if (offset < max) {
6402 point = xmlUTF8Strpos(to->stringval, offset);
6403 if (point)
6404 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6405 }
6406 } else
6407 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6408
6409 /* Step to next character in input */
6410 cptr++;
6411 if ( ch & 0x80 ) {
6412 /* if not simple ascii, verify proper format */
6413 if ( (ch & 0xc0) != 0xc0 ) {
6414 xmlGenericError(xmlGenericErrorContext,
6415 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6416 break;
6417 }
6418 /* then skip over remaining bytes for this char */
6419 while ( (ch <<= 1) & 0x80 )
6420 if ( (*cptr++ & 0xc0) != 0x80 ) {
6421 xmlGenericError(xmlGenericErrorContext,
6422 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6423 break;
6424 }
6425 if (ch & 0x80) /* must have had error encountered */
6426 break;
6427 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006428 }
Owen Taylor3473f882001-02-23 17:55:21 +00006429 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006430 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6431 xmlBufferFree(target);
6432 xmlXPathFreeObject(str);
6433 xmlXPathFreeObject(from);
6434 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006435}
6436
6437/**
6438 * xmlXPathBooleanFunction:
6439 * @ctxt: the XPath Parser context
6440 * @nargs: the number of arguments
6441 *
6442 * Implement the boolean() XPath function
6443 * boolean boolean(object)
6444 * he boolean function converts its argument to a boolean as follows:
6445 * - a number is true if and only if it is neither positive or
6446 * negative zero nor NaN
6447 * - a node-set is true if and only if it is non-empty
6448 * - a string is true if and only if its length is non-zero
6449 */
6450void
6451xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6452 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006453
6454 CHECK_ARITY(1);
6455 cur = valuePop(ctxt);
6456 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006457 cur = xmlXPathConvertBoolean(cur);
6458 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006459}
6460
6461/**
6462 * xmlXPathNotFunction:
6463 * @ctxt: the XPath Parser context
6464 * @nargs: the number of arguments
6465 *
6466 * Implement the not() XPath function
6467 * boolean not(boolean)
6468 * The not function returns true if its argument is false,
6469 * and false otherwise.
6470 */
6471void
6472xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6473 CHECK_ARITY(1);
6474 CAST_TO_BOOLEAN;
6475 CHECK_TYPE(XPATH_BOOLEAN);
6476 ctxt->value->boolval = ! ctxt->value->boolval;
6477}
6478
6479/**
6480 * xmlXPathTrueFunction:
6481 * @ctxt: the XPath Parser context
6482 * @nargs: the number of arguments
6483 *
6484 * Implement the true() XPath function
6485 * boolean true()
6486 */
6487void
6488xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6489 CHECK_ARITY(0);
6490 valuePush(ctxt, xmlXPathNewBoolean(1));
6491}
6492
6493/**
6494 * xmlXPathFalseFunction:
6495 * @ctxt: the XPath Parser context
6496 * @nargs: the number of arguments
6497 *
6498 * Implement the false() XPath function
6499 * boolean false()
6500 */
6501void
6502xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6503 CHECK_ARITY(0);
6504 valuePush(ctxt, xmlXPathNewBoolean(0));
6505}
6506
6507/**
6508 * xmlXPathLangFunction:
6509 * @ctxt: the XPath Parser context
6510 * @nargs: the number of arguments
6511 *
6512 * Implement the lang() XPath function
6513 * boolean lang(string)
6514 * The lang function returns true or false depending on whether the
6515 * language of the context node as specified by xml:lang attributes
6516 * is the same as or is a sublanguage of the language specified by
6517 * the argument string. The language of the context node is determined
6518 * by the value of the xml:lang attribute on the context node, or, if
6519 * the context node has no xml:lang attribute, by the value of the
6520 * xml:lang attribute on the nearest ancestor of the context node that
6521 * has an xml:lang attribute. If there is no such attribute, then lang
6522 * returns false. If there is such an attribute, then lang returns
6523 * true if the attribute value is equal to the argument ignoring case,
6524 * or if there is some suffix starting with - such that the attribute
6525 * value is equal to the argument ignoring that suffix of the attribute
6526 * value and ignoring case.
6527 */
6528void
6529xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6530 xmlXPathObjectPtr val;
6531 const xmlChar *theLang;
6532 const xmlChar *lang;
6533 int ret = 0;
6534 int i;
6535
6536 CHECK_ARITY(1);
6537 CAST_TO_STRING;
6538 CHECK_TYPE(XPATH_STRING);
6539 val = valuePop(ctxt);
6540 lang = val->stringval;
6541 theLang = xmlNodeGetLang(ctxt->context->node);
6542 if ((theLang != NULL) && (lang != NULL)) {
6543 for (i = 0;lang[i] != 0;i++)
6544 if (toupper(lang[i]) != toupper(theLang[i]))
6545 goto not_equal;
6546 ret = 1;
6547 }
6548not_equal:
6549 xmlXPathFreeObject(val);
6550 valuePush(ctxt, xmlXPathNewBoolean(ret));
6551}
6552
6553/**
6554 * xmlXPathNumberFunction:
6555 * @ctxt: the XPath Parser context
6556 * @nargs: the number of arguments
6557 *
6558 * Implement the number() XPath function
6559 * number number(object?)
6560 */
6561void
6562xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6563 xmlXPathObjectPtr cur;
6564 double res;
6565
6566 if (nargs == 0) {
6567 if (ctxt->context->node == NULL) {
6568 valuePush(ctxt, xmlXPathNewFloat(0.0));
6569 } else {
6570 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6571
6572 res = xmlXPathStringEvalNumber(content);
6573 valuePush(ctxt, xmlXPathNewFloat(res));
6574 xmlFree(content);
6575 }
6576 return;
6577 }
6578
6579 CHECK_ARITY(1);
6580 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006581 cur = xmlXPathConvertNumber(cur);
6582 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006583}
6584
6585/**
6586 * xmlXPathSumFunction:
6587 * @ctxt: the XPath Parser context
6588 * @nargs: the number of arguments
6589 *
6590 * Implement the sum() XPath function
6591 * number sum(node-set)
6592 * The sum function returns the sum of the values of the nodes in
6593 * the argument node-set.
6594 */
6595void
6596xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6597 xmlXPathObjectPtr cur;
6598 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006599 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00006600
6601 CHECK_ARITY(1);
6602 if ((ctxt->value == NULL) ||
6603 ((ctxt->value->type != XPATH_NODESET) &&
6604 (ctxt->value->type != XPATH_XSLT_TREE)))
6605 XP_ERROR(XPATH_INVALID_TYPE);
6606 cur = valuePop(ctxt);
6607
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006608 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006609 valuePush(ctxt, xmlXPathNewFloat(0.0));
6610 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006611 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
6612 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006613 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006614 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00006615 }
6616 xmlXPathFreeObject(cur);
6617}
6618
6619/**
6620 * xmlXPathFloorFunction:
6621 * @ctxt: the XPath Parser context
6622 * @nargs: the number of arguments
6623 *
6624 * Implement the floor() XPath function
6625 * number floor(number)
6626 * The floor function returns the largest (closest to positive infinity)
6627 * number that is not greater than the argument and that is an integer.
6628 */
6629void
6630xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006631 double f;
6632
Owen Taylor3473f882001-02-23 17:55:21 +00006633 CHECK_ARITY(1);
6634 CAST_TO_NUMBER;
6635 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006636
6637 f = (double)((int) ctxt->value->floatval);
6638 if (f != ctxt->value->floatval) {
6639 if (ctxt->value->floatval > 0)
6640 ctxt->value->floatval = f;
6641 else
6642 ctxt->value->floatval = f - 1;
6643 }
Owen Taylor3473f882001-02-23 17:55:21 +00006644}
6645
6646/**
6647 * xmlXPathCeilingFunction:
6648 * @ctxt: the XPath Parser context
6649 * @nargs: the number of arguments
6650 *
6651 * Implement the ceiling() XPath function
6652 * number ceiling(number)
6653 * The ceiling function returns the smallest (closest to negative infinity)
6654 * number that is not less than the argument and that is an integer.
6655 */
6656void
6657xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6658 double f;
6659
6660 CHECK_ARITY(1);
6661 CAST_TO_NUMBER;
6662 CHECK_TYPE(XPATH_NUMBER);
6663
6664#if 0
6665 ctxt->value->floatval = ceil(ctxt->value->floatval);
6666#else
6667 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006668 if (f != ctxt->value->floatval) {
6669 if (ctxt->value->floatval > 0)
6670 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00006671 else {
6672 if (ctxt->value->floatval < 0 && f == 0)
6673 ctxt->value->floatval = xmlXPathNZERO;
6674 else
6675 ctxt->value->floatval = f;
6676 }
6677
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006678 }
Owen Taylor3473f882001-02-23 17:55:21 +00006679#endif
6680}
6681
6682/**
6683 * xmlXPathRoundFunction:
6684 * @ctxt: the XPath Parser context
6685 * @nargs: the number of arguments
6686 *
6687 * Implement the round() XPath function
6688 * number round(number)
6689 * The round function returns the number that is closest to the
6690 * argument and that is an integer. If there are two such numbers,
6691 * then the one that is even is returned.
6692 */
6693void
6694xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6695 double f;
6696
6697 CHECK_ARITY(1);
6698 CAST_TO_NUMBER;
6699 CHECK_TYPE(XPATH_NUMBER);
6700
Daniel Veillardcda96922001-08-21 10:56:31 +00006701 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
6702 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
6703 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00006704 (ctxt->value->floatval == 0.0))
6705 return;
6706
Owen Taylor3473f882001-02-23 17:55:21 +00006707 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006708 if (ctxt->value->floatval < 0) {
6709 if (ctxt->value->floatval < f - 0.5)
6710 ctxt->value->floatval = f - 1;
6711 else
6712 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00006713 if (ctxt->value->floatval == 0)
6714 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006715 } else {
6716 if (ctxt->value->floatval < f + 0.5)
6717 ctxt->value->floatval = f;
6718 else
6719 ctxt->value->floatval = f + 1;
6720 }
Owen Taylor3473f882001-02-23 17:55:21 +00006721}
6722
6723/************************************************************************
6724 * *
6725 * The Parser *
6726 * *
6727 ************************************************************************/
6728
6729/*
6730 * a couple of forward declarations since we use a recursive call based
6731 * implementation.
6732 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006733static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006734static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006735static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006736#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006737static void xmlXPathCompRelLocationPath(xmlXPathParserContextPtr ctxt);
6738#define xmlXPathCompRelativeLocationPath xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00006739#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006740static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006741#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00006742static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
6743 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00006744
6745/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00006746 * xmlXPathCurrentChar:
6747 * @ctxt: the XPath parser context
6748 * @cur: pointer to the beginning of the char
6749 * @len: pointer to the length of the char read
6750 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006751 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00006752 * bytes in the input buffer.
6753 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006754 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00006755 */
6756
6757static int
6758xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
6759 unsigned char c;
6760 unsigned int val;
6761 const xmlChar *cur;
6762
6763 if (ctxt == NULL)
6764 return(0);
6765 cur = ctxt->cur;
6766
6767 /*
6768 * We are supposed to handle UTF8, check it's valid
6769 * From rfc2044: encoding of the Unicode values on UTF-8:
6770 *
6771 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
6772 * 0000 0000-0000 007F 0xxxxxxx
6773 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
6774 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
6775 *
6776 * Check for the 0x110000 limit too
6777 */
6778 c = *cur;
6779 if (c & 0x80) {
6780 if ((cur[1] & 0xc0) != 0x80)
6781 goto encoding_error;
6782 if ((c & 0xe0) == 0xe0) {
6783
6784 if ((cur[2] & 0xc0) != 0x80)
6785 goto encoding_error;
6786 if ((c & 0xf0) == 0xf0) {
6787 if (((c & 0xf8) != 0xf0) ||
6788 ((cur[3] & 0xc0) != 0x80))
6789 goto encoding_error;
6790 /* 4-byte code */
6791 *len = 4;
6792 val = (cur[0] & 0x7) << 18;
6793 val |= (cur[1] & 0x3f) << 12;
6794 val |= (cur[2] & 0x3f) << 6;
6795 val |= cur[3] & 0x3f;
6796 } else {
6797 /* 3-byte code */
6798 *len = 3;
6799 val = (cur[0] & 0xf) << 12;
6800 val |= (cur[1] & 0x3f) << 6;
6801 val |= cur[2] & 0x3f;
6802 }
6803 } else {
6804 /* 2-byte code */
6805 *len = 2;
6806 val = (cur[0] & 0x1f) << 6;
6807 val |= cur[1] & 0x3f;
6808 }
6809 if (!IS_CHAR(val)) {
6810 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
6811 }
6812 return(val);
6813 } else {
6814 /* 1-byte code */
6815 *len = 1;
6816 return((int) *cur);
6817 }
6818encoding_error:
6819 /*
6820 * If we detect an UTF8 error that probably mean that the
6821 * input encoding didn't get properly advertized in the
6822 * declaration header. Report the error and switch the encoding
6823 * to ISO-Latin-1 (if you don't like this policy, just declare the
6824 * encoding !)
6825 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00006826 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00006827 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00006828}
6829
6830/**
Owen Taylor3473f882001-02-23 17:55:21 +00006831 * xmlXPathParseNCName:
6832 * @ctxt: the XPath Parser context
6833 *
6834 * parse an XML namespace non qualified name.
6835 *
6836 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
6837 *
6838 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
6839 * CombiningChar | Extender
6840 *
6841 * Returns the namespace name or NULL
6842 */
6843
6844xmlChar *
6845xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00006846 const xmlChar *in;
6847 xmlChar *ret;
6848 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006849
Daniel Veillard2156a562001-04-28 12:24:34 +00006850 /*
6851 * Accelerator for simple ASCII names
6852 */
6853 in = ctxt->cur;
6854 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6855 ((*in >= 0x41) && (*in <= 0x5A)) ||
6856 (*in == '_')) {
6857 in++;
6858 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6859 ((*in >= 0x41) && (*in <= 0x5A)) ||
6860 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00006861 (*in == '_') || (*in == '.') ||
6862 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00006863 in++;
6864 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
6865 (*in == '[') || (*in == ']') || (*in == ':') ||
6866 (*in == '@') || (*in == '*')) {
6867 count = in - ctxt->cur;
6868 if (count == 0)
6869 return(NULL);
6870 ret = xmlStrndup(ctxt->cur, count);
6871 ctxt->cur = in;
6872 return(ret);
6873 }
6874 }
6875 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00006876}
6877
Daniel Veillard2156a562001-04-28 12:24:34 +00006878
Owen Taylor3473f882001-02-23 17:55:21 +00006879/**
6880 * xmlXPathParseQName:
6881 * @ctxt: the XPath Parser context
6882 * @prefix: a xmlChar **
6883 *
6884 * parse an XML qualified name
6885 *
6886 * [NS 5] QName ::= (Prefix ':')? LocalPart
6887 *
6888 * [NS 6] Prefix ::= NCName
6889 *
6890 * [NS 7] LocalPart ::= NCName
6891 *
6892 * Returns the function returns the local part, and prefix is updated
6893 * to get the Prefix if any.
6894 */
6895
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006896static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006897xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
6898 xmlChar *ret = NULL;
6899
6900 *prefix = NULL;
6901 ret = xmlXPathParseNCName(ctxt);
6902 if (CUR == ':') {
6903 *prefix = ret;
6904 NEXT;
6905 ret = xmlXPathParseNCName(ctxt);
6906 }
6907 return(ret);
6908}
6909
6910/**
6911 * xmlXPathParseName:
6912 * @ctxt: the XPath Parser context
6913 *
6914 * parse an XML name
6915 *
6916 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
6917 * CombiningChar | Extender
6918 *
6919 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
6920 *
6921 * Returns the namespace name or NULL
6922 */
6923
6924xmlChar *
6925xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006926 const xmlChar *in;
6927 xmlChar *ret;
6928 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006929
Daniel Veillard61d80a22001-04-27 17:13:01 +00006930 /*
6931 * Accelerator for simple ASCII names
6932 */
6933 in = ctxt->cur;
6934 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6935 ((*in >= 0x41) && (*in <= 0x5A)) ||
6936 (*in == '_') || (*in == ':')) {
6937 in++;
6938 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6939 ((*in >= 0x41) && (*in <= 0x5A)) ||
6940 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00006941 (*in == '_') || (*in == '-') ||
6942 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00006943 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00006944 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006945 count = in - ctxt->cur;
6946 ret = xmlStrndup(ctxt->cur, count);
6947 ctxt->cur = in;
6948 return(ret);
6949 }
6950 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006951 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00006952}
6953
Daniel Veillard61d80a22001-04-27 17:13:01 +00006954static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00006955xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006956 xmlChar buf[XML_MAX_NAMELEN + 5];
6957 int len = 0, l;
6958 int c;
6959
6960 /*
6961 * Handler for more complex cases
6962 */
6963 c = CUR_CHAR(l);
6964 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00006965 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
6966 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00006967 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00006968 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006969 return(NULL);
6970 }
6971
6972 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
6973 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
6974 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00006975 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00006976 (IS_COMBINING(c)) ||
6977 (IS_EXTENDER(c)))) {
6978 COPY_BUF(l,buf,len,c);
6979 NEXTL(l);
6980 c = CUR_CHAR(l);
6981 if (len >= XML_MAX_NAMELEN) {
6982 /*
6983 * Okay someone managed to make a huge name, so he's ready to pay
6984 * for the processing speed.
6985 */
6986 xmlChar *buffer;
6987 int max = len * 2;
6988
6989 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
6990 if (buffer == NULL) {
6991 XP_ERROR0(XPATH_MEMORY_ERROR);
6992 }
6993 memcpy(buffer, buf, len);
6994 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
6995 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00006996 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00006997 (IS_COMBINING(c)) ||
6998 (IS_EXTENDER(c))) {
6999 if (len + 10 > max) {
7000 max *= 2;
7001 buffer = (xmlChar *) xmlRealloc(buffer,
7002 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007003 if (buffer == NULL) {
7004 XP_ERROR0(XPATH_MEMORY_ERROR);
7005 }
7006 }
7007 COPY_BUF(l,buffer,len,c);
7008 NEXTL(l);
7009 c = CUR_CHAR(l);
7010 }
7011 buffer[len] = 0;
7012 return(buffer);
7013 }
7014 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007015 if (len == 0)
7016 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007017 return(xmlStrndup(buf, len));
7018}
Owen Taylor3473f882001-02-23 17:55:21 +00007019/**
7020 * xmlXPathStringEvalNumber:
7021 * @str: A string to scan
7022 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00007023 * [30a] Float ::= Number ('e' Digits?)?
7024 *
Owen Taylor3473f882001-02-23 17:55:21 +00007025 * [30] Number ::= Digits ('.' Digits?)?
7026 * | '.' Digits
7027 * [31] Digits ::= [0-9]+
7028 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007029 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00007030 * In complement of the Number expression, this function also handles
7031 * negative values : '-' Number.
7032 *
7033 * Returns the double value.
7034 */
7035double
7036xmlXPathStringEvalNumber(const xmlChar *str) {
7037 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00007038 double ret;
Owen Taylor3473f882001-02-23 17:55:21 +00007039 double mult = 1;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007040 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007041 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007042 int exponent = 0;
7043 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007044#ifdef __GNUC__
7045 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007046 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007047#endif
Bjorn Reese70a9da52001-04-21 16:57:29 +00007048
Owen Taylor3473f882001-02-23 17:55:21 +00007049 while (IS_BLANK(*cur)) cur++;
7050 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7051 return(xmlXPathNAN);
7052 }
7053 if (*cur == '-') {
7054 isneg = 1;
7055 cur++;
7056 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007057
7058#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007059 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007060 * tmp/temp is a workaround against a gcc compiler bug
7061 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007062 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007063 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007064 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007065 ret = ret * 10;
7066 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00007067 ok = 1;
7068 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00007069 temp = (double) tmp;
7070 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007071 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007072#else
Daniel Veillard7b416132002-03-07 08:36:03 +00007073 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007074 while ((*cur >= '0') && (*cur <= '9')) {
7075 ret = ret * 10 + (*cur - '0');
7076 ok = 1;
7077 cur++;
7078 }
7079#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007080
Owen Taylor3473f882001-02-23 17:55:21 +00007081 if (*cur == '.') {
7082 cur++;
7083 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7084 return(xmlXPathNAN);
7085 }
7086 while ((*cur >= '0') && (*cur <= '9')) {
7087 mult /= 10;
7088 ret = ret + (*cur - '0') * mult;
7089 cur++;
7090 }
7091 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007092 if ((*cur == 'e') || (*cur == 'E')) {
7093 cur++;
7094 if (*cur == '-') {
7095 is_exponent_negative = 1;
7096 cur++;
7097 }
7098 while ((*cur >= '0') && (*cur <= '9')) {
7099 exponent = exponent * 10 + (*cur - '0');
7100 cur++;
7101 }
7102 }
Owen Taylor3473f882001-02-23 17:55:21 +00007103 while (IS_BLANK(*cur)) cur++;
7104 if (*cur != 0) return(xmlXPathNAN);
7105 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007106 if (is_exponent_negative) exponent = -exponent;
7107 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007108 return(ret);
7109}
7110
7111/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007112 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007113 * @ctxt: the XPath Parser context
7114 *
7115 * [30] Number ::= Digits ('.' Digits?)?
7116 * | '.' Digits
7117 * [31] Digits ::= [0-9]+
7118 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007119 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007120 *
7121 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007122static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007123xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7124{
Owen Taylor3473f882001-02-23 17:55:21 +00007125 double ret = 0.0;
7126 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007127 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007128 int exponent = 0;
7129 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007130#ifdef __GNUC__
7131 unsigned long tmp = 0;
7132 double temp;
7133#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007134
7135 CHECK_ERROR;
7136 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7137 XP_ERROR(XPATH_NUMBER_ERROR);
7138 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007139#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007140 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007141 * tmp/temp is a workaround against a gcc compiler bug
7142 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007143 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007144 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007145 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007146 ret = ret * 10;
7147 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007148 ok = 1;
7149 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007150 temp = (double) tmp;
7151 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007152 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007153#else
7154 ret = 0;
7155 while ((CUR >= '0') && (CUR <= '9')) {
7156 ret = ret * 10 + (CUR - '0');
7157 ok = 1;
7158 NEXT;
7159 }
7160#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007161 if (CUR == '.') {
7162 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007163 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7164 XP_ERROR(XPATH_NUMBER_ERROR);
7165 }
7166 while ((CUR >= '0') && (CUR <= '9')) {
7167 mult /= 10;
7168 ret = ret + (CUR - '0') * mult;
7169 NEXT;
7170 }
Owen Taylor3473f882001-02-23 17:55:21 +00007171 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007172 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007173 NEXT;
7174 if (CUR == '-') {
7175 is_exponent_negative = 1;
7176 NEXT;
7177 }
7178 while ((CUR >= '0') && (CUR <= '9')) {
7179 exponent = exponent * 10 + (CUR - '0');
7180 NEXT;
7181 }
7182 if (is_exponent_negative)
7183 exponent = -exponent;
7184 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007185 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007186 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007187 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007188}
7189
7190/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007191 * xmlXPathParseLiteral:
7192 * @ctxt: the XPath Parser context
7193 *
7194 * Parse a Literal
7195 *
7196 * [29] Literal ::= '"' [^"]* '"'
7197 * | "'" [^']* "'"
7198 *
7199 * Returns the value found or NULL in case of error
7200 */
7201static xmlChar *
7202xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7203 const xmlChar *q;
7204 xmlChar *ret = NULL;
7205
7206 if (CUR == '"') {
7207 NEXT;
7208 q = CUR_PTR;
7209 while ((IS_CHAR(CUR)) && (CUR != '"'))
7210 NEXT;
7211 if (!IS_CHAR(CUR)) {
7212 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7213 } else {
7214 ret = xmlStrndup(q, CUR_PTR - q);
7215 NEXT;
7216 }
7217 } else if (CUR == '\'') {
7218 NEXT;
7219 q = CUR_PTR;
7220 while ((IS_CHAR(CUR)) && (CUR != '\''))
7221 NEXT;
7222 if (!IS_CHAR(CUR)) {
7223 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7224 } else {
7225 ret = xmlStrndup(q, CUR_PTR - q);
7226 NEXT;
7227 }
7228 } else {
7229 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7230 }
7231 return(ret);
7232}
7233
7234/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007235 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007236 * @ctxt: the XPath Parser context
7237 *
7238 * Parse a Literal and push it on the stack.
7239 *
7240 * [29] Literal ::= '"' [^"]* '"'
7241 * | "'" [^']* "'"
7242 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007243 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007244 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007245static void
7246xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007247 const xmlChar *q;
7248 xmlChar *ret = NULL;
7249
7250 if (CUR == '"') {
7251 NEXT;
7252 q = CUR_PTR;
7253 while ((IS_CHAR(CUR)) && (CUR != '"'))
7254 NEXT;
7255 if (!IS_CHAR(CUR)) {
7256 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7257 } else {
7258 ret = xmlStrndup(q, CUR_PTR - q);
7259 NEXT;
7260 }
7261 } else if (CUR == '\'') {
7262 NEXT;
7263 q = CUR_PTR;
7264 while ((IS_CHAR(CUR)) && (CUR != '\''))
7265 NEXT;
7266 if (!IS_CHAR(CUR)) {
7267 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7268 } else {
7269 ret = xmlStrndup(q, CUR_PTR - q);
7270 NEXT;
7271 }
7272 } else {
7273 XP_ERROR(XPATH_START_LITERAL_ERROR);
7274 }
7275 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007276 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7277 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007278 xmlFree(ret);
7279}
7280
7281/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007282 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007283 * @ctxt: the XPath Parser context
7284 *
7285 * Parse a VariableReference, evaluate it and push it on the stack.
7286 *
7287 * The variable bindings consist of a mapping from variable names
7288 * to variable values. The value of a variable is an object, which
7289 * of any of the types that are possible for the value of an expression,
7290 * and may also be of additional types not specified here.
7291 *
7292 * Early evaluation is possible since:
7293 * The variable bindings [...] used to evaluate a subexpression are
7294 * always the same as those used to evaluate the containing expression.
7295 *
7296 * [36] VariableReference ::= '$' QName
7297 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007298static void
7299xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007300 xmlChar *name;
7301 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007302
7303 SKIP_BLANKS;
7304 if (CUR != '$') {
7305 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7306 }
7307 NEXT;
7308 name = xmlXPathParseQName(ctxt, &prefix);
7309 if (name == NULL) {
7310 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7311 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007312 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007313 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7314 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007315 SKIP_BLANKS;
7316}
7317
7318/**
7319 * xmlXPathIsNodeType:
7320 * @ctxt: the XPath Parser context
7321 * @name: a name string
7322 *
7323 * Is the name given a NodeType one.
7324 *
7325 * [38] NodeType ::= 'comment'
7326 * | 'text'
7327 * | 'processing-instruction'
7328 * | 'node'
7329 *
7330 * Returns 1 if true 0 otherwise
7331 */
7332int
7333xmlXPathIsNodeType(const xmlChar *name) {
7334 if (name == NULL)
7335 return(0);
7336
Daniel Veillard1971ee22002-01-31 20:29:19 +00007337 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007338 return(1);
7339 if (xmlStrEqual(name, BAD_CAST "text"))
7340 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007341 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007342 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007343 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007344 return(1);
7345 return(0);
7346}
7347
7348/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007349 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007350 * @ctxt: the XPath Parser context
7351 *
7352 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7353 * [17] Argument ::= Expr
7354 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007355 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007356 * pushed on the stack
7357 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007358static void
7359xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007360 xmlChar *name;
7361 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007362 int nbargs = 0;
7363
7364 name = xmlXPathParseQName(ctxt, &prefix);
7365 if (name == NULL) {
7366 XP_ERROR(XPATH_EXPR_ERROR);
7367 }
7368 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007369#ifdef DEBUG_EXPR
7370 if (prefix == NULL)
7371 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7372 name);
7373 else
7374 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7375 prefix, name);
7376#endif
7377
Owen Taylor3473f882001-02-23 17:55:21 +00007378 if (CUR != '(') {
7379 XP_ERROR(XPATH_EXPR_ERROR);
7380 }
7381 NEXT;
7382 SKIP_BLANKS;
7383
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007384 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007385 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007386 int op1 = ctxt->comp->last;
7387 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007388 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007389 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007390 nbargs++;
7391 if (CUR == ')') break;
7392 if (CUR != ',') {
7393 XP_ERROR(XPATH_EXPR_ERROR);
7394 }
7395 NEXT;
7396 SKIP_BLANKS;
7397 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007398 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7399 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007400 NEXT;
7401 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007402}
7403
7404/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007405 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007406 * @ctxt: the XPath Parser context
7407 *
7408 * [15] PrimaryExpr ::= VariableReference
7409 * | '(' Expr ')'
7410 * | Literal
7411 * | Number
7412 * | FunctionCall
7413 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007414 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007415 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007416static void
7417xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007418 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007419 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007420 else if (CUR == '(') {
7421 NEXT;
7422 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007423 xmlXPathCompileExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007424 if (CUR != ')') {
7425 XP_ERROR(XPATH_EXPR_ERROR);
7426 }
7427 NEXT;
7428 SKIP_BLANKS;
Daniel Veillard01917aa2002-04-10 11:30:41 +00007429 } else if (IS_DIGIT(CUR) || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007430 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007431 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007432 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007433 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007434 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007435 }
7436 SKIP_BLANKS;
7437}
7438
7439/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007440 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007441 * @ctxt: the XPath Parser context
7442 *
7443 * [20] FilterExpr ::= PrimaryExpr
7444 * | FilterExpr Predicate
7445 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007446 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007447 * Square brackets are used to filter expressions in the same way that
7448 * they are used in location paths. It is an error if the expression to
7449 * be filtered does not evaluate to a node-set. The context node list
7450 * used for evaluating the expression in square brackets is the node-set
7451 * to be filtered listed in document order.
7452 */
7453
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007454static void
7455xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
7456 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007457 CHECK_ERROR;
7458 SKIP_BLANKS;
7459
7460 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007461 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00007462 SKIP_BLANKS;
7463 }
7464
7465
7466}
7467
7468/**
7469 * xmlXPathScanName:
7470 * @ctxt: the XPath Parser context
7471 *
7472 * Trickery: parse an XML name but without consuming the input flow
7473 * Needed to avoid insanity in the parser state.
7474 *
7475 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7476 * CombiningChar | Extender
7477 *
7478 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7479 *
7480 * [6] Names ::= Name (S Name)*
7481 *
7482 * Returns the Name parsed or NULL
7483 */
7484
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007485static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007486xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7487 xmlChar buf[XML_MAX_NAMELEN];
7488 int len = 0;
7489
7490 SKIP_BLANKS;
7491 if (!IS_LETTER(CUR) && (CUR != '_') &&
7492 (CUR != ':')) {
7493 return(NULL);
7494 }
7495
7496 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7497 (NXT(len) == '.') || (NXT(len) == '-') ||
7498 (NXT(len) == '_') || (NXT(len) == ':') ||
7499 (IS_COMBINING(NXT(len))) ||
7500 (IS_EXTENDER(NXT(len)))) {
7501 buf[len] = NXT(len);
7502 len++;
7503 if (len >= XML_MAX_NAMELEN) {
7504 xmlGenericError(xmlGenericErrorContext,
7505 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
7506 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7507 (NXT(len) == '.') || (NXT(len) == '-') ||
7508 (NXT(len) == '_') || (NXT(len) == ':') ||
7509 (IS_COMBINING(NXT(len))) ||
7510 (IS_EXTENDER(NXT(len))))
7511 len++;
7512 break;
7513 }
7514 }
7515 return(xmlStrndup(buf, len));
7516}
7517
7518/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007519 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007520 * @ctxt: the XPath Parser context
7521 *
7522 * [19] PathExpr ::= LocationPath
7523 * | FilterExpr
7524 * | FilterExpr '/' RelativeLocationPath
7525 * | FilterExpr '//' RelativeLocationPath
7526 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007527 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007528 * The / operator and // operators combine an arbitrary expression
7529 * and a relative location path. It is an error if the expression
7530 * does not evaluate to a node-set.
7531 * The / operator does composition in the same way as when / is
7532 * used in a location path. As in location paths, // is short for
7533 * /descendant-or-self::node()/.
7534 */
7535
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007536static void
7537xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007538 int lc = 1; /* Should we branch to LocationPath ? */
7539 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7540
7541 SKIP_BLANKS;
7542 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
Daniel Veillard01917aa2002-04-10 11:30:41 +00007543 (CUR == '\'') || (CUR == '"') || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00007544 lc = 0;
7545 } else if (CUR == '*') {
7546 /* relative or absolute location path */
7547 lc = 1;
7548 } else if (CUR == '/') {
7549 /* relative or absolute location path */
7550 lc = 1;
7551 } else if (CUR == '@') {
7552 /* relative abbreviated attribute location path */
7553 lc = 1;
7554 } else if (CUR == '.') {
7555 /* relative abbreviated attribute location path */
7556 lc = 1;
7557 } else {
7558 /*
7559 * Problem is finding if we have a name here whether it's:
7560 * - a nodetype
7561 * - a function call in which case it's followed by '('
7562 * - an axis in which case it's followed by ':'
7563 * - a element name
7564 * We do an a priori analysis here rather than having to
7565 * maintain parsed token content through the recursive function
7566 * calls. This looks uglier but makes the code quite easier to
7567 * read/write/debug.
7568 */
7569 SKIP_BLANKS;
7570 name = xmlXPathScanName(ctxt);
7571 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7572#ifdef DEBUG_STEP
7573 xmlGenericError(xmlGenericErrorContext,
7574 "PathExpr: Axis\n");
7575#endif
7576 lc = 1;
7577 xmlFree(name);
7578 } else if (name != NULL) {
7579 int len =xmlStrlen(name);
7580 int blank = 0;
7581
7582
7583 while (NXT(len) != 0) {
7584 if (NXT(len) == '/') {
7585 /* element name */
7586#ifdef DEBUG_STEP
7587 xmlGenericError(xmlGenericErrorContext,
7588 "PathExpr: AbbrRelLocation\n");
7589#endif
7590 lc = 1;
7591 break;
7592 } else if (IS_BLANK(NXT(len))) {
7593 /* skip to next */
7594 blank = 1;
7595 } else if (NXT(len) == ':') {
7596#ifdef DEBUG_STEP
7597 xmlGenericError(xmlGenericErrorContext,
7598 "PathExpr: AbbrRelLocation\n");
7599#endif
7600 lc = 1;
7601 break;
7602 } else if ((NXT(len) == '(')) {
7603 /* Note Type or Function */
7604 if (xmlXPathIsNodeType(name)) {
7605#ifdef DEBUG_STEP
7606 xmlGenericError(xmlGenericErrorContext,
7607 "PathExpr: Type search\n");
7608#endif
7609 lc = 1;
7610 } else {
7611#ifdef DEBUG_STEP
7612 xmlGenericError(xmlGenericErrorContext,
7613 "PathExpr: function call\n");
7614#endif
7615 lc = 0;
7616 }
7617 break;
7618 } else if ((NXT(len) == '[')) {
7619 /* element name */
7620#ifdef DEBUG_STEP
7621 xmlGenericError(xmlGenericErrorContext,
7622 "PathExpr: AbbrRelLocation\n");
7623#endif
7624 lc = 1;
7625 break;
7626 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
7627 (NXT(len) == '=')) {
7628 lc = 1;
7629 break;
7630 } else {
7631 lc = 1;
7632 break;
7633 }
7634 len++;
7635 }
7636 if (NXT(len) == 0) {
7637#ifdef DEBUG_STEP
7638 xmlGenericError(xmlGenericErrorContext,
7639 "PathExpr: AbbrRelLocation\n");
7640#endif
7641 /* element name */
7642 lc = 1;
7643 }
7644 xmlFree(name);
7645 } else {
7646 /* make sure all cases are covered explicitely */
7647 XP_ERROR(XPATH_EXPR_ERROR);
7648 }
7649 }
7650
7651 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007652 if (CUR == '/') {
7653 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
7654 } else {
7655 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007656 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007657 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007658 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007659 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007660 CHECK_ERROR;
7661 if ((CUR == '/') && (NXT(1) == '/')) {
7662 SKIP(2);
7663 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007664
7665 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7666 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
7667 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
7668
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007669 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007670 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007671 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007672 }
7673 }
7674 SKIP_BLANKS;
7675}
7676
7677/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007678 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007679 * @ctxt: the XPath Parser context
7680 *
7681 * [18] UnionExpr ::= PathExpr
7682 * | UnionExpr '|' PathExpr
7683 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007684 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007685 */
7686
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007687static void
7688xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
7689 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007690 CHECK_ERROR;
7691 SKIP_BLANKS;
7692 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007693 int op1 = ctxt->comp->last;
7694 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007695
7696 NEXT;
7697 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007698 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007699
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007700 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
7701
Owen Taylor3473f882001-02-23 17:55:21 +00007702 SKIP_BLANKS;
7703 }
Owen Taylor3473f882001-02-23 17:55:21 +00007704}
7705
7706/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007707 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007708 * @ctxt: the XPath Parser context
7709 *
7710 * [27] UnaryExpr ::= UnionExpr
7711 * | '-' UnaryExpr
7712 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007713 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007714 */
7715
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007716static void
7717xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007718 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007719 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007720
7721 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00007722 while (CUR == '-') {
7723 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007724 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007725 NEXT;
7726 SKIP_BLANKS;
7727 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007728
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007729 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007730 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007731 if (found) {
7732 if (minus)
7733 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
7734 else
7735 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007736 }
7737}
7738
7739/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007740 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007741 * @ctxt: the XPath Parser context
7742 *
7743 * [26] MultiplicativeExpr ::= UnaryExpr
7744 * | MultiplicativeExpr MultiplyOperator UnaryExpr
7745 * | MultiplicativeExpr 'div' UnaryExpr
7746 * | MultiplicativeExpr 'mod' UnaryExpr
7747 * [34] MultiplyOperator ::= '*'
7748 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007749 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007750 */
7751
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007752static void
7753xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
7754 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007755 CHECK_ERROR;
7756 SKIP_BLANKS;
7757 while ((CUR == '*') ||
7758 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
7759 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
7760 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007761 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007762
7763 if (CUR == '*') {
7764 op = 0;
7765 NEXT;
7766 } else if (CUR == 'd') {
7767 op = 1;
7768 SKIP(3);
7769 } else if (CUR == 'm') {
7770 op = 2;
7771 SKIP(3);
7772 }
7773 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007774 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007775 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007776 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007777 SKIP_BLANKS;
7778 }
7779}
7780
7781/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007782 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007783 * @ctxt: the XPath Parser context
7784 *
7785 * [25] AdditiveExpr ::= MultiplicativeExpr
7786 * | AdditiveExpr '+' MultiplicativeExpr
7787 * | AdditiveExpr '-' MultiplicativeExpr
7788 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007789 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007790 */
7791
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007792static void
7793xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007794
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007795 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007796 CHECK_ERROR;
7797 SKIP_BLANKS;
7798 while ((CUR == '+') || (CUR == '-')) {
7799 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007800 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007801
7802 if (CUR == '+') plus = 1;
7803 else plus = 0;
7804 NEXT;
7805 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007806 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007807 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007808 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007809 SKIP_BLANKS;
7810 }
7811}
7812
7813/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007814 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007815 * @ctxt: the XPath Parser context
7816 *
7817 * [24] RelationalExpr ::= AdditiveExpr
7818 * | RelationalExpr '<' AdditiveExpr
7819 * | RelationalExpr '>' AdditiveExpr
7820 * | RelationalExpr '<=' AdditiveExpr
7821 * | RelationalExpr '>=' AdditiveExpr
7822 *
7823 * A <= B > C is allowed ? Answer from James, yes with
7824 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
7825 * which is basically what got implemented.
7826 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007827 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00007828 * on the stack
7829 */
7830
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007831static void
7832xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
7833 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007834 CHECK_ERROR;
7835 SKIP_BLANKS;
7836 while ((CUR == '<') ||
7837 (CUR == '>') ||
7838 ((CUR == '<') && (NXT(1) == '=')) ||
7839 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007840 int inf, strict;
7841 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007842
7843 if (CUR == '<') inf = 1;
7844 else inf = 0;
7845 if (NXT(1) == '=') strict = 0;
7846 else strict = 1;
7847 NEXT;
7848 if (!strict) NEXT;
7849 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007850 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007851 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007852 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00007853 SKIP_BLANKS;
7854 }
7855}
7856
7857/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007858 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007859 * @ctxt: the XPath Parser context
7860 *
7861 * [23] EqualityExpr ::= RelationalExpr
7862 * | EqualityExpr '=' RelationalExpr
7863 * | EqualityExpr '!=' RelationalExpr
7864 *
7865 * A != B != C is allowed ? Answer from James, yes with
7866 * (RelationalExpr = RelationalExpr) = RelationalExpr
7867 * (RelationalExpr != RelationalExpr) != RelationalExpr
7868 * which is basically what got implemented.
7869 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007870 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007871 *
7872 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007873static void
7874xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
7875 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007876 CHECK_ERROR;
7877 SKIP_BLANKS;
7878 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007879 int eq;
7880 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007881
7882 if (CUR == '=') eq = 1;
7883 else eq = 0;
7884 NEXT;
7885 if (!eq) NEXT;
7886 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007887 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007888 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007889 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007890 SKIP_BLANKS;
7891 }
7892}
7893
7894/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007895 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007896 * @ctxt: the XPath Parser context
7897 *
7898 * [22] AndExpr ::= EqualityExpr
7899 * | AndExpr 'and' EqualityExpr
7900 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007901 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007902 *
7903 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007904static void
7905xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
7906 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007907 CHECK_ERROR;
7908 SKIP_BLANKS;
7909 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007910 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007911 SKIP(3);
7912 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007913 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007914 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007915 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007916 SKIP_BLANKS;
7917 }
7918}
7919
7920/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007921 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007922 * @ctxt: the XPath Parser context
7923 *
7924 * [14] Expr ::= OrExpr
7925 * [21] OrExpr ::= AndExpr
7926 * | OrExpr 'or' AndExpr
7927 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007928 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00007929 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007930static void
7931xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
7932 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007933 CHECK_ERROR;
7934 SKIP_BLANKS;
7935 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007936 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007937 SKIP(2);
7938 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007939 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007940 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007941 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
7942 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00007943 SKIP_BLANKS;
7944 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007945 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
7946 /* more ops could be optimized too */
7947 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
7948 }
Owen Taylor3473f882001-02-23 17:55:21 +00007949}
7950
7951/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007952 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00007953 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007954 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00007955 *
7956 * [8] Predicate ::= '[' PredicateExpr ']'
7957 * [9] PredicateExpr ::= Expr
7958 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007959 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00007960 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007961static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007962xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007963 int op1 = ctxt->comp->last;
7964
7965 SKIP_BLANKS;
7966 if (CUR != '[') {
7967 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7968 }
7969 NEXT;
7970 SKIP_BLANKS;
7971
7972 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007973 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007974 CHECK_ERROR;
7975
7976 if (CUR != ']') {
7977 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7978 }
7979
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007980 if (filter)
7981 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
7982 else
7983 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007984
7985 NEXT;
7986 SKIP_BLANKS;
7987}
7988
7989/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007990 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00007991 * @ctxt: the XPath Parser context
7992 * @test: pointer to a xmlXPathTestVal
7993 * @type: pointer to a xmlXPathTypeVal
7994 * @prefix: placeholder for a possible name prefix
7995 *
7996 * [7] NodeTest ::= NameTest
7997 * | NodeType '(' ')'
7998 * | 'processing-instruction' '(' Literal ')'
7999 *
8000 * [37] NameTest ::= '*'
8001 * | NCName ':' '*'
8002 * | QName
8003 * [38] NodeType ::= 'comment'
8004 * | 'text'
8005 * | 'processing-instruction'
8006 * | 'node'
8007 *
8008 * Returns the name found and update @test, @type and @prefix appropriately
8009 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008010static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008011xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8012 xmlXPathTypeVal *type, const xmlChar **prefix,
8013 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008014 int blanks;
8015
8016 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8017 STRANGE;
8018 return(NULL);
8019 }
8020 *type = 0;
8021 *test = 0;
8022 *prefix = NULL;
8023 SKIP_BLANKS;
8024
8025 if ((name == NULL) && (CUR == '*')) {
8026 /*
8027 * All elements
8028 */
8029 NEXT;
8030 *test = NODE_TEST_ALL;
8031 return(NULL);
8032 }
8033
8034 if (name == NULL)
8035 name = xmlXPathParseNCName(ctxt);
8036 if (name == NULL) {
8037 XP_ERROR0(XPATH_EXPR_ERROR);
8038 }
8039
8040 blanks = IS_BLANK(CUR);
8041 SKIP_BLANKS;
8042 if (CUR == '(') {
8043 NEXT;
8044 /*
8045 * NodeType or PI search
8046 */
8047 if (xmlStrEqual(name, BAD_CAST "comment"))
8048 *type = NODE_TYPE_COMMENT;
8049 else if (xmlStrEqual(name, BAD_CAST "node"))
8050 *type = NODE_TYPE_NODE;
8051 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8052 *type = NODE_TYPE_PI;
8053 else if (xmlStrEqual(name, BAD_CAST "text"))
8054 *type = NODE_TYPE_TEXT;
8055 else {
8056 if (name != NULL)
8057 xmlFree(name);
8058 XP_ERROR0(XPATH_EXPR_ERROR);
8059 }
8060
8061 *test = NODE_TEST_TYPE;
8062
8063 SKIP_BLANKS;
8064 if (*type == NODE_TYPE_PI) {
8065 /*
8066 * Specific case: search a PI by name.
8067 */
Owen Taylor3473f882001-02-23 17:55:21 +00008068 if (name != NULL)
8069 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008070 name = NULL;
8071 if (CUR != ')') {
8072 name = xmlXPathParseLiteral(ctxt);
8073 CHECK_ERROR 0;
8074 SKIP_BLANKS;
8075 }
Owen Taylor3473f882001-02-23 17:55:21 +00008076 }
8077 if (CUR != ')') {
8078 if (name != NULL)
8079 xmlFree(name);
8080 XP_ERROR0(XPATH_UNCLOSED_ERROR);
8081 }
8082 NEXT;
8083 return(name);
8084 }
8085 *test = NODE_TEST_NAME;
8086 if ((!blanks) && (CUR == ':')) {
8087 NEXT;
8088
8089 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008090 * Since currently the parser context don't have a
8091 * namespace list associated:
8092 * The namespace name for this prefix can be computed
8093 * only at evaluation time. The compilation is done
8094 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008095 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008096#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008097 *prefix = xmlXPathNsLookup(ctxt->context, name);
8098 if (name != NULL)
8099 xmlFree(name);
8100 if (*prefix == NULL) {
8101 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8102 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008103#else
8104 *prefix = name;
8105#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008106
8107 if (CUR == '*') {
8108 /*
8109 * All elements
8110 */
8111 NEXT;
8112 *test = NODE_TEST_ALL;
8113 return(NULL);
8114 }
8115
8116 name = xmlXPathParseNCName(ctxt);
8117 if (name == NULL) {
8118 XP_ERROR0(XPATH_EXPR_ERROR);
8119 }
8120 }
8121 return(name);
8122}
8123
8124/**
8125 * xmlXPathIsAxisName:
8126 * @name: a preparsed name token
8127 *
8128 * [6] AxisName ::= 'ancestor'
8129 * | 'ancestor-or-self'
8130 * | 'attribute'
8131 * | 'child'
8132 * | 'descendant'
8133 * | 'descendant-or-self'
8134 * | 'following'
8135 * | 'following-sibling'
8136 * | 'namespace'
8137 * | 'parent'
8138 * | 'preceding'
8139 * | 'preceding-sibling'
8140 * | 'self'
8141 *
8142 * Returns the axis or 0
8143 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008144static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008145xmlXPathIsAxisName(const xmlChar *name) {
8146 xmlXPathAxisVal ret = 0;
8147 switch (name[0]) {
8148 case 'a':
8149 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8150 ret = AXIS_ANCESTOR;
8151 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8152 ret = AXIS_ANCESTOR_OR_SELF;
8153 if (xmlStrEqual(name, BAD_CAST "attribute"))
8154 ret = AXIS_ATTRIBUTE;
8155 break;
8156 case 'c':
8157 if (xmlStrEqual(name, BAD_CAST "child"))
8158 ret = AXIS_CHILD;
8159 break;
8160 case 'd':
8161 if (xmlStrEqual(name, BAD_CAST "descendant"))
8162 ret = AXIS_DESCENDANT;
8163 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8164 ret = AXIS_DESCENDANT_OR_SELF;
8165 break;
8166 case 'f':
8167 if (xmlStrEqual(name, BAD_CAST "following"))
8168 ret = AXIS_FOLLOWING;
8169 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8170 ret = AXIS_FOLLOWING_SIBLING;
8171 break;
8172 case 'n':
8173 if (xmlStrEqual(name, BAD_CAST "namespace"))
8174 ret = AXIS_NAMESPACE;
8175 break;
8176 case 'p':
8177 if (xmlStrEqual(name, BAD_CAST "parent"))
8178 ret = AXIS_PARENT;
8179 if (xmlStrEqual(name, BAD_CAST "preceding"))
8180 ret = AXIS_PRECEDING;
8181 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8182 ret = AXIS_PRECEDING_SIBLING;
8183 break;
8184 case 's':
8185 if (xmlStrEqual(name, BAD_CAST "self"))
8186 ret = AXIS_SELF;
8187 break;
8188 }
8189 return(ret);
8190}
8191
8192/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008193 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008194 * @ctxt: the XPath Parser context
8195 *
8196 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8197 * | AbbreviatedStep
8198 *
8199 * [12] AbbreviatedStep ::= '.' | '..'
8200 *
8201 * [5] AxisSpecifier ::= AxisName '::'
8202 * | AbbreviatedAxisSpecifier
8203 *
8204 * [13] AbbreviatedAxisSpecifier ::= '@'?
8205 *
8206 * Modified for XPtr range support as:
8207 *
8208 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8209 * | AbbreviatedStep
8210 * | 'range-to' '(' Expr ')' Predicate*
8211 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008212 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008213 * A location step of . is short for self::node(). This is
8214 * particularly useful in conjunction with //. For example, the
8215 * location path .//para is short for
8216 * self::node()/descendant-or-self::node()/child::para
8217 * and so will select all para descendant elements of the context
8218 * node.
8219 * Similarly, a location step of .. is short for parent::node().
8220 * For example, ../title is short for parent::node()/child::title
8221 * and so will select the title children of the parent of the context
8222 * node.
8223 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008224static void
8225xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008226#ifdef LIBXML_XPTR_ENABLED
8227 int rangeto = 0;
8228 int op2 = -1;
8229#endif
8230
Owen Taylor3473f882001-02-23 17:55:21 +00008231 SKIP_BLANKS;
8232 if ((CUR == '.') && (NXT(1) == '.')) {
8233 SKIP(2);
8234 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008235 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8236 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008237 } else if (CUR == '.') {
8238 NEXT;
8239 SKIP_BLANKS;
8240 } else {
8241 xmlChar *name = NULL;
8242 const xmlChar *prefix = NULL;
8243 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008244 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008245 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008246 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008247
8248 /*
8249 * The modification needed for XPointer change to the production
8250 */
8251#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008252 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008253 name = xmlXPathParseNCName(ctxt);
8254 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008255 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008256 xmlFree(name);
8257 SKIP_BLANKS;
8258 if (CUR != '(') {
8259 XP_ERROR(XPATH_EXPR_ERROR);
8260 }
8261 NEXT;
8262 SKIP_BLANKS;
8263
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008264 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008265 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008266 CHECK_ERROR;
8267
8268 SKIP_BLANKS;
8269 if (CUR != ')') {
8270 XP_ERROR(XPATH_EXPR_ERROR);
8271 }
8272 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008273 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008274 goto eval_predicates;
8275 }
8276 }
8277#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008278 if (CUR == '*') {
8279 axis = AXIS_CHILD;
8280 } else {
8281 if (name == NULL)
8282 name = xmlXPathParseNCName(ctxt);
8283 if (name != NULL) {
8284 axis = xmlXPathIsAxisName(name);
8285 if (axis != 0) {
8286 SKIP_BLANKS;
8287 if ((CUR == ':') && (NXT(1) == ':')) {
8288 SKIP(2);
8289 xmlFree(name);
8290 name = NULL;
8291 } else {
8292 /* an element name can conflict with an axis one :-\ */
8293 axis = AXIS_CHILD;
8294 }
Owen Taylor3473f882001-02-23 17:55:21 +00008295 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008296 axis = AXIS_CHILD;
8297 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008298 } else if (CUR == '@') {
8299 NEXT;
8300 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008301 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008302 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008303 }
Owen Taylor3473f882001-02-23 17:55:21 +00008304 }
8305
8306 CHECK_ERROR;
8307
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008308 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008309 if (test == 0)
8310 return;
8311
8312#ifdef DEBUG_STEP
8313 xmlGenericError(xmlGenericErrorContext,
8314 "Basis : computing new set\n");
8315#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008316
Owen Taylor3473f882001-02-23 17:55:21 +00008317#ifdef DEBUG_STEP
8318 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008319 if (ctxt->value == NULL)
8320 xmlGenericError(xmlGenericErrorContext, "no value\n");
8321 else if (ctxt->value->nodesetval == NULL)
8322 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8323 else
8324 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008325#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008326
8327eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008328 op1 = ctxt->comp->last;
8329 ctxt->comp->last = -1;
8330
Owen Taylor3473f882001-02-23 17:55:21 +00008331 SKIP_BLANKS;
8332 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008333 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008334 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008335
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008336#ifdef LIBXML_XPTR_ENABLED
8337 if (rangeto) {
8338 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8339 } else
8340#endif
8341 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8342 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008343
Owen Taylor3473f882001-02-23 17:55:21 +00008344 }
8345#ifdef DEBUG_STEP
8346 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008347 if (ctxt->value == NULL)
8348 xmlGenericError(xmlGenericErrorContext, "no value\n");
8349 else if (ctxt->value->nodesetval == NULL)
8350 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8351 else
8352 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8353 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008354#endif
8355}
8356
8357/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008358 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008359 * @ctxt: the XPath Parser context
8360 *
8361 * [3] RelativeLocationPath ::= Step
8362 * | RelativeLocationPath '/' Step
8363 * | AbbreviatedRelativeLocationPath
8364 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8365 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008366 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008367 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008368static void
Owen Taylor3473f882001-02-23 17:55:21 +00008369#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008370xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008371#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008372xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008373#endif
8374(xmlXPathParserContextPtr ctxt) {
8375 SKIP_BLANKS;
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,
8380 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008381 } else if (CUR == '/') {
8382 NEXT;
8383 SKIP_BLANKS;
8384 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008385 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008386 SKIP_BLANKS;
8387 while (CUR == '/') {
8388 if ((CUR == '/') && (NXT(1) == '/')) {
8389 SKIP(2);
8390 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008391 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008392 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008393 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008394 } else if (CUR == '/') {
8395 NEXT;
8396 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008397 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008398 }
8399 SKIP_BLANKS;
8400 }
8401}
8402
8403/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008404 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008405 * @ctxt: the XPath Parser context
8406 *
8407 * [1] LocationPath ::= RelativeLocationPath
8408 * | AbsoluteLocationPath
8409 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8410 * | AbbreviatedAbsoluteLocationPath
8411 * [10] AbbreviatedAbsoluteLocationPath ::=
8412 * '//' RelativeLocationPath
8413 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008414 * Compile a location path
8415 *
Owen Taylor3473f882001-02-23 17:55:21 +00008416 * // is short for /descendant-or-self::node()/. For example,
8417 * //para is short for /descendant-or-self::node()/child::para and
8418 * so will select any para element in the document (even a para element
8419 * that is a document element will be selected by //para since the
8420 * document element node is a child of the root node); div//para is
8421 * short for div/descendant-or-self::node()/child::para and so will
8422 * select all para descendants of div children.
8423 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008424static void
8425xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008426 SKIP_BLANKS;
8427 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008428 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008429 } else {
8430 while (CUR == '/') {
8431 if ((CUR == '/') && (NXT(1) == '/')) {
8432 SKIP(2);
8433 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008434 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8435 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008436 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008437 } else if (CUR == '/') {
8438 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008439 SKIP_BLANKS;
8440 if ((CUR != 0 ) &&
8441 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
8442 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008443 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008444 }
8445 }
8446 }
8447}
8448
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008449/************************************************************************
8450 * *
8451 * XPath precompiled expression evaluation *
8452 * *
8453 ************************************************************************/
8454
Daniel Veillardf06307e2001-07-03 10:35:50 +00008455static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008456xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8457
8458/**
8459 * xmlXPathNodeCollectAndTest:
8460 * @ctxt: the XPath Parser context
8461 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008462 * @first: pointer to the first element in document order
8463 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008464 *
8465 * This is the function implementing a step: based on the current list
8466 * of nodes, it builds up a new list, looking at all nodes under that
8467 * axis and selecting them it also do the predicate filtering
8468 *
8469 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00008470 *
8471 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008472 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008473static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008474xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008475 xmlXPathStepOpPtr op,
8476 xmlNodePtr * first, xmlNodePtr * last)
8477{
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008478 xmlXPathAxisVal axis = op->value;
8479 xmlXPathTestVal test = op->value2;
8480 xmlXPathTypeVal type = op->value3;
8481 const xmlChar *prefix = op->value4;
8482 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008483 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008484
8485#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008486 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008487#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008488 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008489 xmlNodeSetPtr ret, list;
8490 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008491 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00008492 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008493 xmlNodePtr cur = NULL;
8494 xmlXPathObjectPtr obj;
8495 xmlNodeSetPtr nodelist;
8496 xmlNodePtr tmp;
8497
Daniel Veillardf06307e2001-07-03 10:35:50 +00008498 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008499 obj = valuePop(ctxt);
8500 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00008501 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008502 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008503 URI = xmlXPathNsLookup(ctxt->context, prefix);
8504 if (URI == NULL)
8505 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008506 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008507#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008508 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008509#endif
8510 switch (axis) {
8511 case AXIS_ANCESTOR:
8512#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008513 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008514#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008515 first = NULL;
8516 next = xmlXPathNextAncestor;
8517 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008518 case AXIS_ANCESTOR_OR_SELF:
8519#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008520 xmlGenericError(xmlGenericErrorContext,
8521 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008522#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008523 first = NULL;
8524 next = xmlXPathNextAncestorOrSelf;
8525 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008526 case AXIS_ATTRIBUTE:
8527#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008528 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008529#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008530 first = NULL;
8531 last = NULL;
8532 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00008533 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008534 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008535 case AXIS_CHILD:
8536#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008537 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008538#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008539 last = NULL;
8540 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00008541 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008542 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008543 case AXIS_DESCENDANT:
8544#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008545 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008546#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008547 last = NULL;
8548 next = xmlXPathNextDescendant;
8549 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008550 case AXIS_DESCENDANT_OR_SELF:
8551#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008552 xmlGenericError(xmlGenericErrorContext,
8553 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008554#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008555 last = NULL;
8556 next = xmlXPathNextDescendantOrSelf;
8557 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008558 case AXIS_FOLLOWING:
8559#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008560 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008561#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008562 last = NULL;
8563 next = xmlXPathNextFollowing;
8564 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008565 case AXIS_FOLLOWING_SIBLING:
8566#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008567 xmlGenericError(xmlGenericErrorContext,
8568 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008569#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008570 last = NULL;
8571 next = xmlXPathNextFollowingSibling;
8572 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008573 case AXIS_NAMESPACE:
8574#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008575 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008576#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008577 first = NULL;
8578 last = NULL;
8579 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00008580 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008581 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008582 case AXIS_PARENT:
8583#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008584 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008585#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008586 first = NULL;
8587 next = xmlXPathNextParent;
8588 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008589 case AXIS_PRECEDING:
8590#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008591 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008592#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008593 first = NULL;
8594 next = xmlXPathNextPrecedingInternal;
8595 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008596 case AXIS_PRECEDING_SIBLING:
8597#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008598 xmlGenericError(xmlGenericErrorContext,
8599 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008600#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008601 first = NULL;
8602 next = xmlXPathNextPrecedingSibling;
8603 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008604 case AXIS_SELF:
8605#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008606 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008607#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008608 first = NULL;
8609 last = NULL;
8610 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00008611 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008612 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008613 }
8614 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008615 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008616
8617 nodelist = obj->nodesetval;
8618 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008619 xmlXPathFreeObject(obj);
8620 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8621 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008622 }
8623 addNode = xmlXPathNodeSetAddUnique;
8624 ret = NULL;
8625#ifdef DEBUG_STEP
8626 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008627 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008628 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008629 case NODE_TEST_NONE:
8630 xmlGenericError(xmlGenericErrorContext,
8631 " searching for none !!!\n");
8632 break;
8633 case NODE_TEST_TYPE:
8634 xmlGenericError(xmlGenericErrorContext,
8635 " searching for type %d\n", type);
8636 break;
8637 case NODE_TEST_PI:
8638 xmlGenericError(xmlGenericErrorContext,
8639 " searching for PI !!!\n");
8640 break;
8641 case NODE_TEST_ALL:
8642 xmlGenericError(xmlGenericErrorContext,
8643 " searching for *\n");
8644 break;
8645 case NODE_TEST_NS:
8646 xmlGenericError(xmlGenericErrorContext,
8647 " searching for namespace %s\n",
8648 prefix);
8649 break;
8650 case NODE_TEST_NAME:
8651 xmlGenericError(xmlGenericErrorContext,
8652 " searching for name %s\n", name);
8653 if (prefix != NULL)
8654 xmlGenericError(xmlGenericErrorContext,
8655 " with namespace %s\n", prefix);
8656 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008657 }
8658 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8659#endif
8660 /*
8661 * 2.3 Node Tests
8662 * - For the attribute axis, the principal node type is attribute.
8663 * - For the namespace axis, the principal node type is namespace.
8664 * - For other axes, the principal node type is element.
8665 *
8666 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008667 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008668 * select all element children of the context node
8669 */
8670 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008671 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008672 ctxt->context->node = nodelist->nodeTab[i];
8673
Daniel Veillardf06307e2001-07-03 10:35:50 +00008674 cur = NULL;
8675 list = xmlXPathNodeSetCreate(NULL);
8676 do {
8677 cur = next(ctxt, cur);
8678 if (cur == NULL)
8679 break;
8680 if ((first != NULL) && (*first == cur))
8681 break;
8682 if (((t % 256) == 0) &&
8683 (first != NULL) && (*first != NULL) &&
8684 (xmlXPathCmpNodes(*first, cur) >= 0))
8685 break;
8686 if ((last != NULL) && (*last == cur))
8687 break;
8688 if (((t % 256) == 0) &&
8689 (last != NULL) && (*last != NULL) &&
8690 (xmlXPathCmpNodes(cur, *last) >= 0))
8691 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008692 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008693#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008694 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
8695#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008696 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008697 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008698 ctxt->context->node = tmp;
8699 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008700 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008701 if ((cur->type == type) ||
8702 ((type == NODE_TYPE_NODE) &&
8703 ((cur->type == XML_DOCUMENT_NODE) ||
8704 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8705 (cur->type == XML_ELEMENT_NODE) ||
8706 (cur->type == XML_PI_NODE) ||
8707 (cur->type == XML_COMMENT_NODE) ||
8708 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00008709 (cur->type == XML_TEXT_NODE))) ||
8710 ((type == NODE_TYPE_TEXT) &&
8711 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008712#ifdef DEBUG_STEP
8713 n++;
8714#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008715 addNode(list, cur);
8716 }
8717 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008718 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008719 if (cur->type == XML_PI_NODE) {
8720 if ((name != NULL) &&
8721 (!xmlStrEqual(name, cur->name)))
8722 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008723#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008724 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008725#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008726 addNode(list, cur);
8727 }
8728 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008729 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008730 if (axis == AXIS_ATTRIBUTE) {
8731 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008732#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008733 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008734#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008735 addNode(list, cur);
8736 }
8737 } else if (axis == AXIS_NAMESPACE) {
8738 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008739#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008740 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008741#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008742 xmlXPathNodeSetAddNs(list, ctxt->context->node,
8743 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008744 }
8745 } else {
8746 if (cur->type == XML_ELEMENT_NODE) {
8747 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008748#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008749 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008750#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008751 addNode(list, cur);
8752 } else if ((cur->ns != NULL) &&
8753 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008754#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008755 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008756#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008757 addNode(list, cur);
8758 }
8759 }
8760 }
8761 break;
8762 case NODE_TEST_NS:{
8763 TODO;
8764 break;
8765 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008766 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008767 switch (cur->type) {
8768 case XML_ELEMENT_NODE:
8769 if (xmlStrEqual(name, cur->name)) {
8770 if (prefix == NULL) {
8771 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008772#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008773 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008774#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008775 addNode(list, cur);
8776 }
8777 } else {
8778 if ((cur->ns != NULL) &&
8779 (xmlStrEqual(URI,
8780 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008781#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008782 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008783#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008784 addNode(list, cur);
8785 }
8786 }
8787 }
8788 break;
8789 case XML_ATTRIBUTE_NODE:{
8790 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008791
Daniel Veillardf06307e2001-07-03 10:35:50 +00008792 if (xmlStrEqual(name, attr->name)) {
8793 if (prefix == NULL) {
8794 if ((attr->ns == NULL) ||
8795 (attr->ns->prefix == NULL)) {
8796#ifdef DEBUG_STEP
8797 n++;
8798#endif
8799 addNode(list,
8800 (xmlNodePtr) attr);
8801 }
8802 } else {
8803 if ((attr->ns != NULL) &&
8804 (xmlStrEqual(URI,
8805 attr->ns->
8806 href))) {
8807#ifdef DEBUG_STEP
8808 n++;
8809#endif
8810 addNode(list,
8811 (xmlNodePtr) attr);
8812 }
8813 }
8814 }
8815 break;
8816 }
8817 case XML_NAMESPACE_DECL:
8818 if (cur->type == XML_NAMESPACE_DECL) {
8819 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008820
Daniel Veillardf06307e2001-07-03 10:35:50 +00008821 if ((ns->prefix != NULL) && (name != NULL)
8822 && (xmlStrEqual(ns->prefix, name))) {
8823#ifdef DEBUG_STEP
8824 n++;
8825#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008826 xmlXPathNodeSetAddNs(list,
8827 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008828 }
8829 }
8830 break;
8831 default:
8832 break;
8833 }
8834 break;
8835 break;
8836 }
8837 } while (cur != NULL);
8838
8839 /*
8840 * If there is some predicate filtering do it now
8841 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00008842 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008843 xmlXPathObjectPtr obj2;
8844
8845 valuePush(ctxt, xmlXPathWrapNodeSet(list));
8846 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
8847 CHECK_TYPE0(XPATH_NODESET);
8848 obj2 = valuePop(ctxt);
8849 list = obj2->nodesetval;
8850 obj2->nodesetval = NULL;
8851 xmlXPathFreeObject(obj2);
8852 }
8853 if (ret == NULL) {
8854 ret = list;
8855 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00008856 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008857 xmlXPathFreeNodeSet(list);
8858 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008859 }
8860 ctxt->context->node = tmp;
8861#ifdef DEBUG_STEP
8862 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008863 "\nExamined %d nodes, found %d nodes at that step\n",
8864 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008865#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008866 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00008867 if ((obj->boolval) && (obj->user != NULL)) {
8868 ctxt->value->boolval = 1;
8869 ctxt->value->user = obj->user;
8870 obj->user = NULL;
8871 obj->boolval = 0;
8872 }
8873 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008874 return(t);
8875}
8876
8877/**
8878 * xmlXPathNodeCollectAndTestNth:
8879 * @ctxt: the XPath Parser context
8880 * @op: the XPath precompiled step operation
8881 * @indx: the index to collect
8882 * @first: pointer to the first element in document order
8883 * @last: pointer to the last element in document order
8884 *
8885 * This is the function implementing a step: based on the current list
8886 * of nodes, it builds up a new list, looking at all nodes under that
8887 * axis and selecting them it also do the predicate filtering
8888 *
8889 * Pushes the new NodeSet resulting from the search.
8890 * Returns the number of node traversed
8891 */
8892static int
8893xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
8894 xmlXPathStepOpPtr op, int indx,
8895 xmlNodePtr * first, xmlNodePtr * last)
8896{
8897 xmlXPathAxisVal axis = op->value;
8898 xmlXPathTestVal test = op->value2;
8899 xmlXPathTypeVal type = op->value3;
8900 const xmlChar *prefix = op->value4;
8901 const xmlChar *name = op->value5;
8902 const xmlChar *URI = NULL;
8903 int n = 0, t = 0;
8904
8905 int i;
8906 xmlNodeSetPtr list;
8907 xmlXPathTraversalFunction next = NULL;
8908 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
8909 xmlNodePtr cur = NULL;
8910 xmlXPathObjectPtr obj;
8911 xmlNodeSetPtr nodelist;
8912 xmlNodePtr tmp;
8913
8914 CHECK_TYPE0(XPATH_NODESET);
8915 obj = valuePop(ctxt);
8916 addNode = xmlXPathNodeSetAdd;
8917 if (prefix != NULL) {
8918 URI = xmlXPathNsLookup(ctxt->context, prefix);
8919 if (URI == NULL)
8920 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8921 }
8922#ifdef DEBUG_STEP_NTH
8923 xmlGenericError(xmlGenericErrorContext, "new step : ");
8924 if (first != NULL) {
8925 if (*first != NULL)
8926 xmlGenericError(xmlGenericErrorContext, "first = %s ",
8927 (*first)->name);
8928 else
8929 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
8930 }
8931 if (last != NULL) {
8932 if (*last != NULL)
8933 xmlGenericError(xmlGenericErrorContext, "last = %s ",
8934 (*last)->name);
8935 else
8936 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
8937 }
8938#endif
8939 switch (axis) {
8940 case AXIS_ANCESTOR:
8941#ifdef DEBUG_STEP_NTH
8942 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
8943#endif
8944 first = NULL;
8945 next = xmlXPathNextAncestor;
8946 break;
8947 case AXIS_ANCESTOR_OR_SELF:
8948#ifdef DEBUG_STEP_NTH
8949 xmlGenericError(xmlGenericErrorContext,
8950 "axis 'ancestors-or-self' ");
8951#endif
8952 first = NULL;
8953 next = xmlXPathNextAncestorOrSelf;
8954 break;
8955 case AXIS_ATTRIBUTE:
8956#ifdef DEBUG_STEP_NTH
8957 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
8958#endif
8959 first = NULL;
8960 last = NULL;
8961 next = xmlXPathNextAttribute;
8962 break;
8963 case AXIS_CHILD:
8964#ifdef DEBUG_STEP_NTH
8965 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
8966#endif
8967 last = NULL;
8968 next = xmlXPathNextChild;
8969 break;
8970 case AXIS_DESCENDANT:
8971#ifdef DEBUG_STEP_NTH
8972 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
8973#endif
8974 last = NULL;
8975 next = xmlXPathNextDescendant;
8976 break;
8977 case AXIS_DESCENDANT_OR_SELF:
8978#ifdef DEBUG_STEP_NTH
8979 xmlGenericError(xmlGenericErrorContext,
8980 "axis 'descendant-or-self' ");
8981#endif
8982 last = NULL;
8983 next = xmlXPathNextDescendantOrSelf;
8984 break;
8985 case AXIS_FOLLOWING:
8986#ifdef DEBUG_STEP_NTH
8987 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
8988#endif
8989 last = NULL;
8990 next = xmlXPathNextFollowing;
8991 break;
8992 case AXIS_FOLLOWING_SIBLING:
8993#ifdef DEBUG_STEP_NTH
8994 xmlGenericError(xmlGenericErrorContext,
8995 "axis 'following-siblings' ");
8996#endif
8997 last = NULL;
8998 next = xmlXPathNextFollowingSibling;
8999 break;
9000 case AXIS_NAMESPACE:
9001#ifdef DEBUG_STEP_NTH
9002 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9003#endif
9004 last = NULL;
9005 first = NULL;
9006 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9007 break;
9008 case AXIS_PARENT:
9009#ifdef DEBUG_STEP_NTH
9010 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9011#endif
9012 first = NULL;
9013 next = xmlXPathNextParent;
9014 break;
9015 case AXIS_PRECEDING:
9016#ifdef DEBUG_STEP_NTH
9017 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9018#endif
9019 first = NULL;
9020 next = xmlXPathNextPrecedingInternal;
9021 break;
9022 case AXIS_PRECEDING_SIBLING:
9023#ifdef DEBUG_STEP_NTH
9024 xmlGenericError(xmlGenericErrorContext,
9025 "axis 'preceding-sibling' ");
9026#endif
9027 first = NULL;
9028 next = xmlXPathNextPrecedingSibling;
9029 break;
9030 case AXIS_SELF:
9031#ifdef DEBUG_STEP_NTH
9032 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9033#endif
9034 first = NULL;
9035 last = NULL;
9036 next = xmlXPathNextSelf;
9037 break;
9038 }
9039 if (next == NULL)
9040 return(0);
9041
9042 nodelist = obj->nodesetval;
9043 if (nodelist == NULL) {
9044 xmlXPathFreeObject(obj);
9045 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9046 return(0);
9047 }
9048 addNode = xmlXPathNodeSetAddUnique;
9049#ifdef DEBUG_STEP_NTH
9050 xmlGenericError(xmlGenericErrorContext,
9051 " context contains %d nodes\n", nodelist->nodeNr);
9052 switch (test) {
9053 case NODE_TEST_NONE:
9054 xmlGenericError(xmlGenericErrorContext,
9055 " searching for none !!!\n");
9056 break;
9057 case NODE_TEST_TYPE:
9058 xmlGenericError(xmlGenericErrorContext,
9059 " searching for type %d\n", type);
9060 break;
9061 case NODE_TEST_PI:
9062 xmlGenericError(xmlGenericErrorContext,
9063 " searching for PI !!!\n");
9064 break;
9065 case NODE_TEST_ALL:
9066 xmlGenericError(xmlGenericErrorContext,
9067 " searching for *\n");
9068 break;
9069 case NODE_TEST_NS:
9070 xmlGenericError(xmlGenericErrorContext,
9071 " searching for namespace %s\n",
9072 prefix);
9073 break;
9074 case NODE_TEST_NAME:
9075 xmlGenericError(xmlGenericErrorContext,
9076 " searching for name %s\n", name);
9077 if (prefix != NULL)
9078 xmlGenericError(xmlGenericErrorContext,
9079 " with namespace %s\n", prefix);
9080 break;
9081 }
9082 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9083#endif
9084 /*
9085 * 2.3 Node Tests
9086 * - For the attribute axis, the principal node type is attribute.
9087 * - For the namespace axis, the principal node type is namespace.
9088 * - For other axes, the principal node type is element.
9089 *
9090 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009091 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009092 * select all element children of the context node
9093 */
9094 tmp = ctxt->context->node;
9095 list = xmlXPathNodeSetCreate(NULL);
9096 for (i = 0; i < nodelist->nodeNr; i++) {
9097 ctxt->context->node = nodelist->nodeTab[i];
9098
9099 cur = NULL;
9100 n = 0;
9101 do {
9102 cur = next(ctxt, cur);
9103 if (cur == NULL)
9104 break;
9105 if ((first != NULL) && (*first == cur))
9106 break;
9107 if (((t % 256) == 0) &&
9108 (first != NULL) && (*first != NULL) &&
9109 (xmlXPathCmpNodes(*first, cur) >= 0))
9110 break;
9111 if ((last != NULL) && (*last == cur))
9112 break;
9113 if (((t % 256) == 0) &&
9114 (last != NULL) && (*last != NULL) &&
9115 (xmlXPathCmpNodes(cur, *last) >= 0))
9116 break;
9117 t++;
9118 switch (test) {
9119 case NODE_TEST_NONE:
9120 ctxt->context->node = tmp;
9121 STRANGE return(0);
9122 case NODE_TEST_TYPE:
9123 if ((cur->type == type) ||
9124 ((type == NODE_TYPE_NODE) &&
9125 ((cur->type == XML_DOCUMENT_NODE) ||
9126 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9127 (cur->type == XML_ELEMENT_NODE) ||
9128 (cur->type == XML_PI_NODE) ||
9129 (cur->type == XML_COMMENT_NODE) ||
9130 (cur->type == XML_CDATA_SECTION_NODE) ||
9131 (cur->type == XML_TEXT_NODE)))) {
9132 n++;
9133 if (n == indx)
9134 addNode(list, cur);
9135 }
9136 break;
9137 case NODE_TEST_PI:
9138 if (cur->type == XML_PI_NODE) {
9139 if ((name != NULL) &&
9140 (!xmlStrEqual(name, cur->name)))
9141 break;
9142 n++;
9143 if (n == indx)
9144 addNode(list, cur);
9145 }
9146 break;
9147 case NODE_TEST_ALL:
9148 if (axis == AXIS_ATTRIBUTE) {
9149 if (cur->type == XML_ATTRIBUTE_NODE) {
9150 n++;
9151 if (n == indx)
9152 addNode(list, cur);
9153 }
9154 } else if (axis == AXIS_NAMESPACE) {
9155 if (cur->type == XML_NAMESPACE_DECL) {
9156 n++;
9157 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009158 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9159 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009160 }
9161 } else {
9162 if (cur->type == XML_ELEMENT_NODE) {
9163 if (prefix == NULL) {
9164 n++;
9165 if (n == indx)
9166 addNode(list, cur);
9167 } else if ((cur->ns != NULL) &&
9168 (xmlStrEqual(URI, cur->ns->href))) {
9169 n++;
9170 if (n == indx)
9171 addNode(list, cur);
9172 }
9173 }
9174 }
9175 break;
9176 case NODE_TEST_NS:{
9177 TODO;
9178 break;
9179 }
9180 case NODE_TEST_NAME:
9181 switch (cur->type) {
9182 case XML_ELEMENT_NODE:
9183 if (xmlStrEqual(name, cur->name)) {
9184 if (prefix == NULL) {
9185 if (cur->ns == NULL) {
9186 n++;
9187 if (n == indx)
9188 addNode(list, cur);
9189 }
9190 } else {
9191 if ((cur->ns != NULL) &&
9192 (xmlStrEqual(URI,
9193 cur->ns->href))) {
9194 n++;
9195 if (n == indx)
9196 addNode(list, cur);
9197 }
9198 }
9199 }
9200 break;
9201 case XML_ATTRIBUTE_NODE:{
9202 xmlAttrPtr attr = (xmlAttrPtr) cur;
9203
9204 if (xmlStrEqual(name, attr->name)) {
9205 if (prefix == NULL) {
9206 if ((attr->ns == NULL) ||
9207 (attr->ns->prefix == NULL)) {
9208 n++;
9209 if (n == indx)
9210 addNode(list, cur);
9211 }
9212 } else {
9213 if ((attr->ns != NULL) &&
9214 (xmlStrEqual(URI,
9215 attr->ns->
9216 href))) {
9217 n++;
9218 if (n == indx)
9219 addNode(list, cur);
9220 }
9221 }
9222 }
9223 break;
9224 }
9225 case XML_NAMESPACE_DECL:
9226 if (cur->type == XML_NAMESPACE_DECL) {
9227 xmlNsPtr ns = (xmlNsPtr) cur;
9228
9229 if ((ns->prefix != NULL) && (name != NULL)
9230 && (xmlStrEqual(ns->prefix, name))) {
9231 n++;
9232 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009233 xmlXPathNodeSetAddNs(list,
9234 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009235 }
9236 }
9237 break;
9238 default:
9239 break;
9240 }
9241 break;
9242 break;
9243 }
9244 } while (n < indx);
9245 }
9246 ctxt->context->node = tmp;
9247#ifdef DEBUG_STEP_NTH
9248 xmlGenericError(xmlGenericErrorContext,
9249 "\nExamined %d nodes, found %d nodes at that step\n",
9250 t, list->nodeNr);
9251#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009252 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009253 if ((obj->boolval) && (obj->user != NULL)) {
9254 ctxt->value->boolval = 1;
9255 ctxt->value->user = obj->user;
9256 obj->user = NULL;
9257 obj->boolval = 0;
9258 }
9259 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009260 return(t);
9261}
9262
9263/**
9264 * xmlXPathCompOpEvalFirst:
9265 * @ctxt: the XPath parser context with the compiled expression
9266 * @op: an XPath compiled operation
9267 * @first: the first elem found so far
9268 *
9269 * Evaluate the Precompiled XPath operation searching only the first
9270 * element in document order
9271 *
9272 * Returns the number of examined objects.
9273 */
9274static int
9275xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9276 xmlXPathStepOpPtr op, xmlNodePtr * first)
9277{
9278 int total = 0, cur;
9279 xmlXPathCompExprPtr comp;
9280 xmlXPathObjectPtr arg1, arg2;
9281
Daniel Veillard556c6682001-10-06 09:59:51 +00009282 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009283 comp = ctxt->comp;
9284 switch (op->op) {
9285 case XPATH_OP_END:
9286 return (0);
9287 case XPATH_OP_UNION:
9288 total =
9289 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9290 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009291 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009292 if ((ctxt->value != NULL)
9293 && (ctxt->value->type == XPATH_NODESET)
9294 && (ctxt->value->nodesetval != NULL)
9295 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9296 /*
9297 * limit tree traversing to first node in the result
9298 */
9299 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9300 *first = ctxt->value->nodesetval->nodeTab[0];
9301 }
9302 cur =
9303 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9304 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009305 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009306 CHECK_TYPE0(XPATH_NODESET);
9307 arg2 = valuePop(ctxt);
9308
9309 CHECK_TYPE0(XPATH_NODESET);
9310 arg1 = valuePop(ctxt);
9311
9312 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9313 arg2->nodesetval);
9314 valuePush(ctxt, arg1);
9315 xmlXPathFreeObject(arg2);
9316 /* optimizer */
9317 if (total > cur)
9318 xmlXPathCompSwap(op);
9319 return (total + cur);
9320 case XPATH_OP_ROOT:
9321 xmlXPathRoot(ctxt);
9322 return (0);
9323 case XPATH_OP_NODE:
9324 if (op->ch1 != -1)
9325 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009326 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009327 if (op->ch2 != -1)
9328 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009329 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009330 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9331 return (total);
9332 case XPATH_OP_RESET:
9333 if (op->ch1 != -1)
9334 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009335 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009336 if (op->ch2 != -1)
9337 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009338 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009339 ctxt->context->node = NULL;
9340 return (total);
9341 case XPATH_OP_COLLECT:{
9342 if (op->ch1 == -1)
9343 return (total);
9344
9345 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009346 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009347
9348 /*
9349 * Optimization for [n] selection where n is a number
9350 */
9351 if ((op->ch2 != -1) &&
9352 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9353 (comp->steps[op->ch2].ch1 == -1) &&
9354 (comp->steps[op->ch2].ch2 != -1) &&
9355 (comp->steps[comp->steps[op->ch2].ch2].op ==
9356 XPATH_OP_VALUE)) {
9357 xmlXPathObjectPtr val;
9358
9359 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9360 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9361 int indx = (int) val->floatval;
9362
9363 if (val->floatval == (float) indx) {
9364 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9365 first, NULL);
9366 return (total);
9367 }
9368 }
9369 }
9370 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9371 return (total);
9372 }
9373 case XPATH_OP_VALUE:
9374 valuePush(ctxt,
9375 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9376 return (0);
9377 case XPATH_OP_SORT:
9378 if (op->ch1 != -1)
9379 total +=
9380 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9381 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009382 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009383 if ((ctxt->value != NULL)
9384 && (ctxt->value->type == XPATH_NODESET)
9385 && (ctxt->value->nodesetval != NULL))
9386 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9387 return (total);
9388 default:
9389 return (xmlXPathCompOpEval(ctxt, op));
9390 }
9391}
9392
9393/**
9394 * xmlXPathCompOpEvalLast:
9395 * @ctxt: the XPath parser context with the compiled expression
9396 * @op: an XPath compiled operation
9397 * @last: the last elem found so far
9398 *
9399 * Evaluate the Precompiled XPath operation searching only the last
9400 * element in document order
9401 *
9402 * Returns the number of node traversed
9403 */
9404static int
9405xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9406 xmlNodePtr * last)
9407{
9408 int total = 0, cur;
9409 xmlXPathCompExprPtr comp;
9410 xmlXPathObjectPtr arg1, arg2;
9411
Daniel Veillard556c6682001-10-06 09:59:51 +00009412 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009413 comp = ctxt->comp;
9414 switch (op->op) {
9415 case XPATH_OP_END:
9416 return (0);
9417 case XPATH_OP_UNION:
9418 total =
9419 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009420 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009421 if ((ctxt->value != NULL)
9422 && (ctxt->value->type == XPATH_NODESET)
9423 && (ctxt->value->nodesetval != NULL)
9424 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9425 /*
9426 * limit tree traversing to first node in the result
9427 */
9428 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9429 *last =
9430 ctxt->value->nodesetval->nodeTab[ctxt->value->
9431 nodesetval->nodeNr -
9432 1];
9433 }
9434 cur =
9435 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009436 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009437 if ((ctxt->value != NULL)
9438 && (ctxt->value->type == XPATH_NODESET)
9439 && (ctxt->value->nodesetval != NULL)
9440 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9441 }
9442 CHECK_TYPE0(XPATH_NODESET);
9443 arg2 = valuePop(ctxt);
9444
9445 CHECK_TYPE0(XPATH_NODESET);
9446 arg1 = valuePop(ctxt);
9447
9448 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9449 arg2->nodesetval);
9450 valuePush(ctxt, arg1);
9451 xmlXPathFreeObject(arg2);
9452 /* optimizer */
9453 if (total > cur)
9454 xmlXPathCompSwap(op);
9455 return (total + cur);
9456 case XPATH_OP_ROOT:
9457 xmlXPathRoot(ctxt);
9458 return (0);
9459 case XPATH_OP_NODE:
9460 if (op->ch1 != -1)
9461 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009462 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009463 if (op->ch2 != -1)
9464 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009465 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009466 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9467 return (total);
9468 case XPATH_OP_RESET:
9469 if (op->ch1 != -1)
9470 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009471 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009472 if (op->ch2 != -1)
9473 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009474 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009475 ctxt->context->node = NULL;
9476 return (total);
9477 case XPATH_OP_COLLECT:{
9478 if (op->ch1 == -1)
9479 return (0);
9480
9481 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009482 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009483
9484 /*
9485 * Optimization for [n] selection where n is a number
9486 */
9487 if ((op->ch2 != -1) &&
9488 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9489 (comp->steps[op->ch2].ch1 == -1) &&
9490 (comp->steps[op->ch2].ch2 != -1) &&
9491 (comp->steps[comp->steps[op->ch2].ch2].op ==
9492 XPATH_OP_VALUE)) {
9493 xmlXPathObjectPtr val;
9494
9495 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9496 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9497 int indx = (int) val->floatval;
9498
9499 if (val->floatval == (float) indx) {
9500 total +=
9501 xmlXPathNodeCollectAndTestNth(ctxt, op,
9502 indx, NULL,
9503 last);
9504 return (total);
9505 }
9506 }
9507 }
9508 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9509 return (total);
9510 }
9511 case XPATH_OP_VALUE:
9512 valuePush(ctxt,
9513 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9514 return (0);
9515 case XPATH_OP_SORT:
9516 if (op->ch1 != -1)
9517 total +=
9518 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9519 last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009520 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009521 if ((ctxt->value != NULL)
9522 && (ctxt->value->type == XPATH_NODESET)
9523 && (ctxt->value->nodesetval != NULL))
9524 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9525 return (total);
9526 default:
9527 return (xmlXPathCompOpEval(ctxt, op));
9528 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009529}
9530
Owen Taylor3473f882001-02-23 17:55:21 +00009531/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009532 * xmlXPathCompOpEval:
9533 * @ctxt: the XPath parser context with the compiled expression
9534 * @op: an XPath compiled operation
9535 *
9536 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009537 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009538 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009539static int
9540xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9541{
9542 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009543 int equal, ret;
9544 xmlXPathCompExprPtr comp;
9545 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009546 xmlNodePtr bak;
9547 xmlDocPtr bakd;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009548
Daniel Veillard556c6682001-10-06 09:59:51 +00009549 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009550 comp = ctxt->comp;
9551 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009552 case XPATH_OP_END:
9553 return (0);
9554 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009555 bakd = ctxt->context->doc;
9556 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009557 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009558 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009559 xmlXPathBooleanFunction(ctxt, 1);
9560 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9561 return (total);
9562 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009563 ctxt->context->doc = bakd;
9564 ctxt->context->node = bak;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009565 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009566 if (ctxt->error) {
9567 xmlXPathFreeObject(arg2);
9568 return(0);
9569 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009570 xmlXPathBooleanFunction(ctxt, 1);
9571 arg1 = valuePop(ctxt);
9572 arg1->boolval &= arg2->boolval;
9573 valuePush(ctxt, arg1);
9574 xmlXPathFreeObject(arg2);
9575 return (total);
9576 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009577 bakd = ctxt->context->doc;
9578 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009579 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009580 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009581 xmlXPathBooleanFunction(ctxt, 1);
9582 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9583 return (total);
9584 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009585 ctxt->context->doc = bakd;
9586 ctxt->context->node = bak;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009587 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009588 if (ctxt->error) {
9589 xmlXPathFreeObject(arg2);
9590 return(0);
9591 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009592 xmlXPathBooleanFunction(ctxt, 1);
9593 arg1 = valuePop(ctxt);
9594 arg1->boolval |= arg2->boolval;
9595 valuePush(ctxt, arg1);
9596 xmlXPathFreeObject(arg2);
9597 return (total);
9598 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009599 bakd = ctxt->context->doc;
9600 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009601 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009602 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009603 ctxt->context->doc = bakd;
9604 ctxt->context->node = bak;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009605 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009606 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009607 equal = xmlXPathEqualValues(ctxt);
9608 if (op->value)
9609 valuePush(ctxt, xmlXPathNewBoolean(equal));
9610 else
9611 valuePush(ctxt, xmlXPathNewBoolean(!equal));
9612 return (total);
9613 case XPATH_OP_CMP:
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 ctxt->context->doc = bakd;
9619 ctxt->context->node = bak;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009620 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009621 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009622 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
9623 valuePush(ctxt, xmlXPathNewBoolean(ret));
9624 return (total);
9625 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009626 bakd = ctxt->context->doc;
9627 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009628 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009629 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009630 if (op->ch2 != -1) {
9631 ctxt->context->doc = bakd;
9632 ctxt->context->node = bak;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009633 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009634 }
Daniel Veillard556c6682001-10-06 09:59:51 +00009635 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009636 if (op->value == 0)
9637 xmlXPathSubValues(ctxt);
9638 else if (op->value == 1)
9639 xmlXPathAddValues(ctxt);
9640 else if (op->value == 2)
9641 xmlXPathValueFlipSign(ctxt);
9642 else if (op->value == 3) {
9643 CAST_TO_NUMBER;
9644 CHECK_TYPE0(XPATH_NUMBER);
9645 }
9646 return (total);
9647 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009648 bakd = ctxt->context->doc;
9649 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009650 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009651 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009652 ctxt->context->doc = bakd;
9653 ctxt->context->node = bak;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009654 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009655 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009656 if (op->value == 0)
9657 xmlXPathMultValues(ctxt);
9658 else if (op->value == 1)
9659 xmlXPathDivValues(ctxt);
9660 else if (op->value == 2)
9661 xmlXPathModValues(ctxt);
9662 return (total);
9663 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009664 bakd = ctxt->context->doc;
9665 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009666 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009667 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009668 ctxt->context->doc = bakd;
9669 ctxt->context->node = bak;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009670 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009671 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009672 CHECK_TYPE0(XPATH_NODESET);
9673 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009674
Daniel Veillardf06307e2001-07-03 10:35:50 +00009675 CHECK_TYPE0(XPATH_NODESET);
9676 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009677
Daniel Veillardf06307e2001-07-03 10:35:50 +00009678 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9679 arg2->nodesetval);
9680 valuePush(ctxt, arg1);
9681 xmlXPathFreeObject(arg2);
9682 return (total);
9683 case XPATH_OP_ROOT:
9684 xmlXPathRoot(ctxt);
9685 return (total);
9686 case XPATH_OP_NODE:
9687 if (op->ch1 != -1)
9688 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009689 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009690 if (op->ch2 != -1)
9691 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009692 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009693 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9694 return (total);
9695 case XPATH_OP_RESET:
9696 if (op->ch1 != -1)
9697 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009698 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009699 if (op->ch2 != -1)
9700 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009701 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009702 ctxt->context->node = NULL;
9703 return (total);
9704 case XPATH_OP_COLLECT:{
9705 if (op->ch1 == -1)
9706 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009707
Daniel Veillardf06307e2001-07-03 10:35:50 +00009708 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009709 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009710
Daniel Veillardf06307e2001-07-03 10:35:50 +00009711 /*
9712 * Optimization for [n] selection where n is a number
9713 */
9714 if ((op->ch2 != -1) &&
9715 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9716 (comp->steps[op->ch2].ch1 == -1) &&
9717 (comp->steps[op->ch2].ch2 != -1) &&
9718 (comp->steps[comp->steps[op->ch2].ch2].op ==
9719 XPATH_OP_VALUE)) {
9720 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +00009721
Daniel Veillardf06307e2001-07-03 10:35:50 +00009722 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9723 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9724 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009725
Daniel Veillardf06307e2001-07-03 10:35:50 +00009726 if (val->floatval == (float) indx) {
9727 total +=
9728 xmlXPathNodeCollectAndTestNth(ctxt, op,
9729 indx, NULL,
9730 NULL);
9731 return (total);
9732 }
9733 }
9734 }
9735 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
9736 return (total);
9737 }
9738 case XPATH_OP_VALUE:
9739 valuePush(ctxt,
9740 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9741 return (total);
9742 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +00009743 xmlXPathObjectPtr val;
9744
Daniel Veillardf06307e2001-07-03 10:35:50 +00009745 if (op->ch1 != -1)
9746 total +=
9747 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009748 if (op->value5 == NULL) {
9749 val = xmlXPathVariableLookup(ctxt->context, op->value4);
9750 if (val == NULL) {
9751 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
9752 return(0);
9753 }
9754 valuePush(ctxt, val);
9755 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009756 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009757
Daniel Veillardf06307e2001-07-03 10:35:50 +00009758 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9759 if (URI == NULL) {
9760 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009761 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009762 op->value4, op->value5);
9763 return (total);
9764 }
Daniel Veillard556c6682001-10-06 09:59:51 +00009765 val = xmlXPathVariableLookupNS(ctxt->context,
9766 op->value4, URI);
9767 if (val == NULL) {
9768 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
9769 return(0);
9770 }
9771 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009772 }
9773 return (total);
9774 }
9775 case XPATH_OP_FUNCTION:{
9776 xmlXPathFunction func;
9777 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +00009778 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009779
9780 if (op->ch1 != -1)
9781 total +=
9782 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009783 if (ctxt->valueNr < op->value) {
9784 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009785 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +00009786 ctxt->error = XPATH_INVALID_OPERAND;
9787 return (total);
9788 }
9789 for (i = 0; i < op->value; i++)
9790 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
9791 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009792 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +00009793 ctxt->error = XPATH_INVALID_OPERAND;
9794 return (total);
9795 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009796 if (op->cache != NULL)
9797 func = (xmlXPathFunction) op->cache;
9798 else {
9799 const xmlChar *URI = NULL;
9800
9801 if (op->value5 == NULL)
9802 func =
9803 xmlXPathFunctionLookup(ctxt->context,
9804 op->value4);
9805 else {
9806 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9807 if (URI == NULL) {
9808 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009809 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009810 op->value4, op->value5);
9811 return (total);
9812 }
9813 func = xmlXPathFunctionLookupNS(ctxt->context,
9814 op->value4, URI);
9815 }
9816 if (func == NULL) {
9817 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009818 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009819 op->value4);
9820 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009821 }
9822 op->cache = (void *) func;
9823 op->cacheURI = (void *) URI;
9824 }
9825 oldFunc = ctxt->context->function;
9826 oldFuncURI = ctxt->context->functionURI;
9827 ctxt->context->function = op->value4;
9828 ctxt->context->functionURI = op->cacheURI;
9829 func(ctxt, op->value);
9830 ctxt->context->function = oldFunc;
9831 ctxt->context->functionURI = oldFuncURI;
9832 return (total);
9833 }
9834 case XPATH_OP_ARG:
9835 if (op->ch1 != -1)
9836 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009837 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009838 if (op->ch2 != -1)
9839 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009840 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009841 return (total);
9842 case XPATH_OP_PREDICATE:
9843 case XPATH_OP_FILTER:{
9844 xmlXPathObjectPtr res;
9845 xmlXPathObjectPtr obj, tmp;
9846 xmlNodeSetPtr newset = NULL;
9847 xmlNodeSetPtr oldset;
9848 xmlNodePtr oldnode;
9849 int i;
9850
9851 /*
9852 * Optimization for ()[1] selection i.e. the first elem
9853 */
9854 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9855 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9856 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
9857 xmlXPathObjectPtr val;
9858
9859 val = comp->steps[op->ch2].value4;
9860 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
9861 (val->floatval == 1.0)) {
9862 xmlNodePtr first = NULL;
9863
9864 total +=
9865 xmlXPathCompOpEvalFirst(ctxt,
9866 &comp->steps[op->ch1],
9867 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009868 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009869 /*
9870 * The nodeset should be in document order,
9871 * Keep only the first value
9872 */
9873 if ((ctxt->value != NULL) &&
9874 (ctxt->value->type == XPATH_NODESET) &&
9875 (ctxt->value->nodesetval != NULL) &&
9876 (ctxt->value->nodesetval->nodeNr > 1))
9877 ctxt->value->nodesetval->nodeNr = 1;
9878 return (total);
9879 }
9880 }
9881 /*
9882 * Optimization for ()[last()] selection i.e. the last elem
9883 */
9884 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9885 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9886 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
9887 int f = comp->steps[op->ch2].ch1;
9888
9889 if ((f != -1) &&
9890 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
9891 (comp->steps[f].value5 == NULL) &&
9892 (comp->steps[f].value == 0) &&
9893 (comp->steps[f].value4 != NULL) &&
9894 (xmlStrEqual
9895 (comp->steps[f].value4, BAD_CAST "last"))) {
9896 xmlNodePtr last = NULL;
9897
9898 total +=
9899 xmlXPathCompOpEvalLast(ctxt,
9900 &comp->steps[op->ch1],
9901 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009902 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009903 /*
9904 * The nodeset should be in document order,
9905 * Keep only the last value
9906 */
9907 if ((ctxt->value != NULL) &&
9908 (ctxt->value->type == XPATH_NODESET) &&
9909 (ctxt->value->nodesetval != NULL) &&
9910 (ctxt->value->nodesetval->nodeTab != NULL) &&
9911 (ctxt->value->nodesetval->nodeNr > 1)) {
9912 ctxt->value->nodesetval->nodeTab[0] =
9913 ctxt->value->nodesetval->nodeTab[ctxt->
9914 value->
9915 nodesetval->
9916 nodeNr -
9917 1];
9918 ctxt->value->nodesetval->nodeNr = 1;
9919 }
9920 return (total);
9921 }
9922 }
9923
9924 if (op->ch1 != -1)
9925 total +=
9926 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009927 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009928 if (op->ch2 == -1)
9929 return (total);
9930 if (ctxt->value == NULL)
9931 return (total);
9932
9933 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009934
9935#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00009936 /*
9937 * Hum are we filtering the result of an XPointer expression
9938 */
9939 if (ctxt->value->type == XPATH_LOCATIONSET) {
9940 xmlLocationSetPtr newlocset = NULL;
9941 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009942
Daniel Veillardf06307e2001-07-03 10:35:50 +00009943 /*
9944 * Extract the old locset, and then evaluate the result of the
9945 * expression for all the element in the locset. use it to grow
9946 * up a new locset.
9947 */
9948 CHECK_TYPE0(XPATH_LOCATIONSET);
9949 obj = valuePop(ctxt);
9950 oldlocset = obj->user;
9951 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009952
Daniel Veillardf06307e2001-07-03 10:35:50 +00009953 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
9954 ctxt->context->contextSize = 0;
9955 ctxt->context->proximityPosition = 0;
9956 if (op->ch2 != -1)
9957 total +=
9958 xmlXPathCompOpEval(ctxt,
9959 &comp->steps[op->ch2]);
9960 res = valuePop(ctxt);
9961 if (res != NULL)
9962 xmlXPathFreeObject(res);
9963 valuePush(ctxt, obj);
9964 CHECK_ERROR0;
9965 return (total);
9966 }
9967 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009968
Daniel Veillardf06307e2001-07-03 10:35:50 +00009969 for (i = 0; i < oldlocset->locNr; i++) {
9970 /*
9971 * Run the evaluation with a node list made of a
9972 * single item in the nodelocset.
9973 */
9974 ctxt->context->node = oldlocset->locTab[i]->user;
9975 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9976 valuePush(ctxt, tmp);
9977 ctxt->context->contextSize = oldlocset->locNr;
9978 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009979
Daniel Veillardf06307e2001-07-03 10:35:50 +00009980 if (op->ch2 != -1)
9981 total +=
9982 xmlXPathCompOpEval(ctxt,
9983 &comp->steps[op->ch2]);
9984 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009985
Daniel Veillardf06307e2001-07-03 10:35:50 +00009986 /*
9987 * The result of the evaluation need to be tested to
9988 * decided whether the filter succeeded or not
9989 */
9990 res = valuePop(ctxt);
9991 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
9992 xmlXPtrLocationSetAdd(newlocset,
9993 xmlXPathObjectCopy
9994 (oldlocset->locTab[i]));
9995 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009996
Daniel Veillardf06307e2001-07-03 10:35:50 +00009997 /*
9998 * Cleanup
9999 */
10000 if (res != NULL)
10001 xmlXPathFreeObject(res);
10002 if (ctxt->value == tmp) {
10003 res = valuePop(ctxt);
10004 xmlXPathFreeObject(res);
10005 }
10006
10007 ctxt->context->node = NULL;
10008 }
10009
10010 /*
10011 * The result is used as the new evaluation locset.
10012 */
10013 xmlXPathFreeObject(obj);
10014 ctxt->context->node = NULL;
10015 ctxt->context->contextSize = -1;
10016 ctxt->context->proximityPosition = -1;
10017 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10018 ctxt->context->node = oldnode;
10019 return (total);
10020 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010021#endif /* LIBXML_XPTR_ENABLED */
10022
Daniel Veillardf06307e2001-07-03 10:35:50 +000010023 /*
10024 * Extract the old set, and then evaluate the result of the
10025 * expression for all the element in the set. use it to grow
10026 * up a new set.
10027 */
10028 CHECK_TYPE0(XPATH_NODESET);
10029 obj = valuePop(ctxt);
10030 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010031
Daniel Veillardf06307e2001-07-03 10:35:50 +000010032 oldnode = ctxt->context->node;
10033 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010034
Daniel Veillardf06307e2001-07-03 10:35:50 +000010035 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10036 ctxt->context->contextSize = 0;
10037 ctxt->context->proximityPosition = 0;
10038 if (op->ch2 != -1)
10039 total +=
10040 xmlXPathCompOpEval(ctxt,
10041 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010042 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010043 res = valuePop(ctxt);
10044 if (res != NULL)
10045 xmlXPathFreeObject(res);
10046 valuePush(ctxt, obj);
10047 ctxt->context->node = oldnode;
10048 CHECK_ERROR0;
10049 } else {
10050 /*
10051 * Initialize the new set.
10052 */
10053 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010054
Daniel Veillardf06307e2001-07-03 10:35:50 +000010055 for (i = 0; i < oldset->nodeNr; i++) {
10056 /*
10057 * Run the evaluation with a node list made of
10058 * a single item in the nodeset.
10059 */
10060 ctxt->context->node = oldset->nodeTab[i];
10061 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10062 valuePush(ctxt, tmp);
10063 ctxt->context->contextSize = oldset->nodeNr;
10064 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010065
Daniel Veillardf06307e2001-07-03 10:35:50 +000010066 if (op->ch2 != -1)
10067 total +=
10068 xmlXPathCompOpEval(ctxt,
10069 &comp->steps[op->ch2]);
10070 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010071
Daniel Veillardf06307e2001-07-03 10:35:50 +000010072 /*
10073 * The result of the evaluation need to be tested to
10074 * decided whether the filter succeeded or not
10075 */
10076 res = valuePop(ctxt);
10077 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10078 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10079 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010080
Daniel Veillardf06307e2001-07-03 10:35:50 +000010081 /*
10082 * Cleanup
10083 */
10084 if (res != NULL)
10085 xmlXPathFreeObject(res);
10086 if (ctxt->value == tmp) {
10087 res = valuePop(ctxt);
10088 xmlXPathFreeObject(res);
10089 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010090
Daniel Veillardf06307e2001-07-03 10:35:50 +000010091 ctxt->context->node = NULL;
10092 }
10093
10094 /*
10095 * The result is used as the new evaluation set.
10096 */
10097 xmlXPathFreeObject(obj);
10098 ctxt->context->node = NULL;
10099 ctxt->context->contextSize = -1;
10100 ctxt->context->proximityPosition = -1;
10101 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10102 }
10103 ctxt->context->node = oldnode;
10104 return (total);
10105 }
10106 case XPATH_OP_SORT:
10107 if (op->ch1 != -1)
10108 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010109 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010110 if ((ctxt->value != NULL) &&
10111 (ctxt->value->type == XPATH_NODESET) &&
10112 (ctxt->value->nodesetval != NULL))
10113 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10114 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010115#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010116 case XPATH_OP_RANGETO:{
10117 xmlXPathObjectPtr range;
10118 xmlXPathObjectPtr res, obj;
10119 xmlXPathObjectPtr tmp;
10120 xmlLocationSetPtr newset = NULL;
10121 xmlNodeSetPtr oldset;
10122 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010123
Daniel Veillardf06307e2001-07-03 10:35:50 +000010124 if (op->ch1 != -1)
10125 total +=
10126 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10127 if (op->ch2 == -1)
10128 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010129
Daniel Veillardf06307e2001-07-03 10:35:50 +000010130 CHECK_TYPE0(XPATH_NODESET);
10131 obj = valuePop(ctxt);
10132 oldset = obj->nodesetval;
10133 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010134
Daniel Veillardf06307e2001-07-03 10:35:50 +000010135 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010136
Daniel Veillardf06307e2001-07-03 10:35:50 +000010137 if (oldset != NULL) {
10138 for (i = 0; i < oldset->nodeNr; i++) {
10139 /*
10140 * Run the evaluation with a node list made of a single item
10141 * in the nodeset.
10142 */
10143 ctxt->context->node = oldset->nodeTab[i];
10144 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10145 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010146
Daniel Veillardf06307e2001-07-03 10:35:50 +000010147 if (op->ch2 != -1)
10148 total +=
10149 xmlXPathCompOpEval(ctxt,
10150 &comp->steps[op->ch2]);
10151 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010152
Daniel Veillardf06307e2001-07-03 10:35:50 +000010153 /*
10154 * The result of the evaluation need to be tested to
10155 * decided whether the filter succeeded or not
10156 */
10157 res = valuePop(ctxt);
10158 range =
10159 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10160 res);
10161 if (range != NULL) {
10162 xmlXPtrLocationSetAdd(newset, range);
10163 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010164
Daniel Veillardf06307e2001-07-03 10:35:50 +000010165 /*
10166 * Cleanup
10167 */
10168 if (res != NULL)
10169 xmlXPathFreeObject(res);
10170 if (ctxt->value == tmp) {
10171 res = valuePop(ctxt);
10172 xmlXPathFreeObject(res);
10173 }
10174
10175 ctxt->context->node = NULL;
10176 }
10177 }
10178
10179 /*
10180 * The result is used as the new evaluation set.
10181 */
10182 xmlXPathFreeObject(obj);
10183 ctxt->context->node = NULL;
10184 ctxt->context->contextSize = -1;
10185 ctxt->context->proximityPosition = -1;
10186 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
10187 return (total);
10188 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010189#endif /* LIBXML_XPTR_ENABLED */
10190 }
10191 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010192 "XPath: unknown precompiled operation %d\n", op->op);
10193 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010194}
10195
10196/**
10197 * xmlXPathRunEval:
10198 * @ctxt: the XPath parser context with the compiled expression
10199 *
10200 * Evaluate the Precompiled XPath expression in the given context.
10201 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010202static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010203xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10204 xmlXPathCompExprPtr comp;
10205
10206 if ((ctxt == NULL) || (ctxt->comp == NULL))
10207 return;
10208
10209 if (ctxt->valueTab == NULL) {
10210 /* Allocate the value stack */
10211 ctxt->valueTab = (xmlXPathObjectPtr *)
10212 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10213 if (ctxt->valueTab == NULL) {
10214 xmlFree(ctxt);
10215 xmlGenericError(xmlGenericErrorContext,
10216 "xmlXPathRunEval: out of memory\n");
10217 return;
10218 }
10219 ctxt->valueNr = 0;
10220 ctxt->valueMax = 10;
10221 ctxt->value = NULL;
10222 }
10223 comp = ctxt->comp;
10224 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10225}
10226
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010227/************************************************************************
10228 * *
10229 * Public interfaces *
10230 * *
10231 ************************************************************************/
10232
10233/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010234 * xmlXPathEvalPredicate:
10235 * @ctxt: the XPath context
10236 * @res: the Predicate Expression evaluation result
10237 *
10238 * Evaluate a predicate result for the current node.
10239 * A PredicateExpr is evaluated by evaluating the Expr and converting
10240 * the result to a boolean. If the result is a number, the result will
10241 * be converted to true if the number is equal to the position of the
10242 * context node in the context node list (as returned by the position
10243 * function) and will be converted to false otherwise; if the result
10244 * is not a number, then the result will be converted as if by a call
10245 * to the boolean function.
10246 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010247 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010248 */
10249int
10250xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
10251 if (res == NULL) return(0);
10252 switch (res->type) {
10253 case XPATH_BOOLEAN:
10254 return(res->boolval);
10255 case XPATH_NUMBER:
10256 return(res->floatval == ctxt->proximityPosition);
10257 case XPATH_NODESET:
10258 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010259 if (res->nodesetval == NULL)
10260 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010261 return(res->nodesetval->nodeNr != 0);
10262 case XPATH_STRING:
10263 return((res->stringval != NULL) &&
10264 (xmlStrlen(res->stringval) != 0));
10265 default:
10266 STRANGE
10267 }
10268 return(0);
10269}
10270
10271/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010272 * xmlXPathEvaluatePredicateResult:
10273 * @ctxt: the XPath Parser context
10274 * @res: the Predicate Expression evaluation result
10275 *
10276 * Evaluate a predicate result for the current node.
10277 * A PredicateExpr is evaluated by evaluating the Expr and converting
10278 * the result to a boolean. If the result is a number, the result will
10279 * be converted to true if the number is equal to the position of the
10280 * context node in the context node list (as returned by the position
10281 * function) and will be converted to false otherwise; if the result
10282 * is not a number, then the result will be converted as if by a call
10283 * to the boolean function.
10284 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010285 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010286 */
10287int
10288xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10289 xmlXPathObjectPtr res) {
10290 if (res == NULL) return(0);
10291 switch (res->type) {
10292 case XPATH_BOOLEAN:
10293 return(res->boolval);
10294 case XPATH_NUMBER:
10295 return(res->floatval == ctxt->context->proximityPosition);
10296 case XPATH_NODESET:
10297 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000010298 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000010299 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010300 return(res->nodesetval->nodeNr != 0);
10301 case XPATH_STRING:
10302 return((res->stringval != NULL) &&
10303 (xmlStrlen(res->stringval) != 0));
10304 default:
10305 STRANGE
10306 }
10307 return(0);
10308}
10309
10310/**
10311 * xmlXPathCompile:
10312 * @str: the XPath expression
10313 *
10314 * Compile an XPath expression
10315 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010316 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010317 * the caller has to free the object.
10318 */
10319xmlXPathCompExprPtr
10320xmlXPathCompile(const xmlChar *str) {
10321 xmlXPathParserContextPtr ctxt;
10322 xmlXPathCompExprPtr comp;
10323
10324 xmlXPathInit();
10325
10326 ctxt = xmlXPathNewParserContext(str, NULL);
10327 xmlXPathCompileExpr(ctxt);
10328
Daniel Veillard40af6492001-04-22 08:50:55 +000010329 if (*ctxt->cur != 0) {
10330 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10331 comp = NULL;
10332 } else {
10333 comp = ctxt->comp;
10334 ctxt->comp = NULL;
10335 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010336 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010337#ifdef DEBUG_EVAL_COUNTS
10338 if (comp != NULL) {
10339 comp->string = xmlStrdup(str);
10340 comp->nb = 0;
10341 }
10342#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010343 return(comp);
10344}
10345
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010346/**
10347 * xmlXPathCompiledEval:
10348 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000010349 * @ctx: the XPath context
10350 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010351 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000010352 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010353 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000010354 * the caller has to free the object.
10355 */
10356xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010357xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000010358 xmlXPathParserContextPtr ctxt;
10359 xmlXPathObjectPtr res, tmp, init = NULL;
10360 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000010361#ifndef LIBXML_THREAD_ENABLED
10362 static int reentance = 0;
10363#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010364
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010365 if ((comp == NULL) || (ctx == NULL))
10366 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010367 xmlXPathInit();
10368
10369 CHECK_CONTEXT(ctx)
10370
Daniel Veillard81463942001-10-16 12:34:39 +000010371#ifndef LIBXML_THREAD_ENABLED
10372 reentance++;
10373 if (reentance > 1)
10374 xmlXPathDisableOptimizer = 1;
10375#endif
10376
Daniel Veillardf06307e2001-07-03 10:35:50 +000010377#ifdef DEBUG_EVAL_COUNTS
10378 comp->nb++;
10379 if ((comp->string != NULL) && (comp->nb > 100)) {
10380 fprintf(stderr, "100 x %s\n", comp->string);
10381 comp->nb = 0;
10382 }
10383#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010384 ctxt = xmlXPathCompParserContext(comp, ctx);
10385 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010386
10387 if (ctxt->value == NULL) {
10388 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010389 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000010390 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000010391 } else {
10392 res = valuePop(ctxt);
10393 }
10394
Daniel Veillardf06307e2001-07-03 10:35:50 +000010395
Owen Taylor3473f882001-02-23 17:55:21 +000010396 do {
10397 tmp = valuePop(ctxt);
10398 if (tmp != NULL) {
10399 if (tmp != init)
10400 stack++;
10401 xmlXPathFreeObject(tmp);
10402 }
10403 } while (tmp != NULL);
10404 if ((stack != 0) && (res != NULL)) {
10405 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010406 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000010407 stack);
10408 }
10409 if (ctxt->error != XPATH_EXPRESSION_OK) {
10410 xmlXPathFreeObject(res);
10411 res = NULL;
10412 }
10413
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010414
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010415 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010416 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000010417#ifndef LIBXML_THREAD_ENABLED
10418 reentance--;
10419#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010420 return(res);
10421}
10422
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010423/**
10424 * xmlXPathEvalExpr:
10425 * @ctxt: the XPath Parser context
10426 *
10427 * Parse and evaluate an XPath expression in the given context,
10428 * then push the result on the context stack
10429 */
10430void
10431xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
10432 xmlXPathCompileExpr(ctxt);
10433 xmlXPathRunEval(ctxt);
10434}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010435
10436/**
10437 * xmlXPathEval:
10438 * @str: the XPath expression
10439 * @ctx: the XPath context
10440 *
10441 * Evaluate the XPath Location Path in the given context.
10442 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010443 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010444 * the caller has to free the object.
10445 */
10446xmlXPathObjectPtr
10447xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
10448 xmlXPathParserContextPtr ctxt;
10449 xmlXPathObjectPtr res, tmp, init = NULL;
10450 int stack = 0;
10451
10452 xmlXPathInit();
10453
10454 CHECK_CONTEXT(ctx)
10455
10456 ctxt = xmlXPathNewParserContext(str, ctx);
10457 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010458
10459 if (ctxt->value == NULL) {
10460 xmlGenericError(xmlGenericErrorContext,
10461 "xmlXPathEval: evaluation failed\n");
10462 res = NULL;
10463 } else if (*ctxt->cur != 0) {
10464 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10465 res = NULL;
10466 } else {
10467 res = valuePop(ctxt);
10468 }
10469
10470 do {
10471 tmp = valuePop(ctxt);
10472 if (tmp != NULL) {
10473 if (tmp != init)
10474 stack++;
10475 xmlXPathFreeObject(tmp);
10476 }
10477 } while (tmp != NULL);
10478 if ((stack != 0) && (res != NULL)) {
10479 xmlGenericError(xmlGenericErrorContext,
10480 "xmlXPathEval: %d object left on the stack\n",
10481 stack);
10482 }
10483 if (ctxt->error != XPATH_EXPRESSION_OK) {
10484 xmlXPathFreeObject(res);
10485 res = NULL;
10486 }
10487
Owen Taylor3473f882001-02-23 17:55:21 +000010488 xmlXPathFreeParserContext(ctxt);
10489 return(res);
10490}
10491
10492/**
10493 * xmlXPathEvalExpression:
10494 * @str: the XPath expression
10495 * @ctxt: the XPath context
10496 *
10497 * Evaluate the XPath expression in the given context.
10498 *
10499 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
10500 * the caller has to free the object.
10501 */
10502xmlXPathObjectPtr
10503xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
10504 xmlXPathParserContextPtr pctxt;
10505 xmlXPathObjectPtr res, tmp;
10506 int stack = 0;
10507
10508 xmlXPathInit();
10509
10510 CHECK_CONTEXT(ctxt)
10511
10512 pctxt = xmlXPathNewParserContext(str, ctxt);
10513 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010514
10515 if (*pctxt->cur != 0) {
10516 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10517 res = NULL;
10518 } else {
10519 res = valuePop(pctxt);
10520 }
10521 do {
10522 tmp = valuePop(pctxt);
10523 if (tmp != NULL) {
10524 xmlXPathFreeObject(tmp);
10525 stack++;
10526 }
10527 } while (tmp != NULL);
10528 if ((stack != 0) && (res != NULL)) {
10529 xmlGenericError(xmlGenericErrorContext,
10530 "xmlXPathEvalExpression: %d object left on the stack\n",
10531 stack);
10532 }
10533 xmlXPathFreeParserContext(pctxt);
10534 return(res);
10535}
10536
10537/**
10538 * xmlXPathRegisterAllFunctions:
10539 * @ctxt: the XPath context
10540 *
10541 * Registers all default XPath functions in this context
10542 */
10543void
10544xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
10545{
10546 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
10547 xmlXPathBooleanFunction);
10548 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
10549 xmlXPathCeilingFunction);
10550 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
10551 xmlXPathCountFunction);
10552 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
10553 xmlXPathConcatFunction);
10554 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
10555 xmlXPathContainsFunction);
10556 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
10557 xmlXPathIdFunction);
10558 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
10559 xmlXPathFalseFunction);
10560 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
10561 xmlXPathFloorFunction);
10562 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
10563 xmlXPathLastFunction);
10564 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
10565 xmlXPathLangFunction);
10566 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
10567 xmlXPathLocalNameFunction);
10568 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
10569 xmlXPathNotFunction);
10570 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
10571 xmlXPathNameFunction);
10572 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
10573 xmlXPathNamespaceURIFunction);
10574 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
10575 xmlXPathNormalizeFunction);
10576 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
10577 xmlXPathNumberFunction);
10578 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
10579 xmlXPathPositionFunction);
10580 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
10581 xmlXPathRoundFunction);
10582 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
10583 xmlXPathStringFunction);
10584 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
10585 xmlXPathStringLengthFunction);
10586 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
10587 xmlXPathStartsWithFunction);
10588 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
10589 xmlXPathSubstringFunction);
10590 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
10591 xmlXPathSubstringBeforeFunction);
10592 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
10593 xmlXPathSubstringAfterFunction);
10594 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
10595 xmlXPathSumFunction);
10596 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
10597 xmlXPathTrueFunction);
10598 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
10599 xmlXPathTranslateFunction);
10600}
10601
10602#endif /* LIBXML_XPATH_ENABLED */