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