blob: bbb02f6aa73e56add20b2d0b78cb2a360afd1c79 [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 */
158int
159xmlXPathGetSign(double val) {
160 return(trio_get_sign(val));
161}
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");
612 } else {
613 fprintf(output, "Object is a number : %0g\n", cur->floatval);
614 }
615 }
Owen Taylor3473f882001-02-23 17:55:21 +0000616 break;
617 case XPATH_STRING:
618 fprintf(output, "Object is a string : ");
619 xmlDebugDumpString(output, cur->stringval);
620 fprintf(output, "\n");
621 break;
622 case XPATH_POINT:
623 fprintf(output, "Object is a point : index %d in node", cur->index);
624 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
625 fprintf(output, "\n");
626 break;
627 case XPATH_RANGE:
628 if ((cur->user2 == NULL) ||
629 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
630 fprintf(output, "Object is a collapsed range :\n");
631 fprintf(output, shift);
632 if (cur->index >= 0)
633 fprintf(output, "index %d in ", cur->index);
634 fprintf(output, "node\n");
635 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
636 depth + 1);
637 } else {
638 fprintf(output, "Object is a range :\n");
639 fprintf(output, shift);
640 fprintf(output, "From ");
641 if (cur->index >= 0)
642 fprintf(output, "index %d in ", cur->index);
643 fprintf(output, "node\n");
644 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
645 depth + 1);
646 fprintf(output, shift);
647 fprintf(output, "To ");
648 if (cur->index2 >= 0)
649 fprintf(output, "index %d in ", cur->index2);
650 fprintf(output, "node\n");
651 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
652 depth + 1);
653 fprintf(output, "\n");
654 }
655 break;
656 case XPATH_LOCATIONSET:
657#if defined(LIBXML_XPTR_ENABLED)
658 fprintf(output, "Object is a Location Set:\n");
659 xmlXPathDebugDumpLocationSet(output,
660 (xmlLocationSetPtr) cur->user, depth);
661#endif
662 break;
663 case XPATH_USERS:
664 fprintf(output, "Object is user defined\n");
665 break;
666 }
667}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000668
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000669static void
670xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000671 xmlXPathStepOpPtr op, int depth) {
672 int i;
673 char shift[100];
674
675 for (i = 0;((i < depth) && (i < 25));i++)
676 shift[2 * i] = shift[2 * i + 1] = ' ';
677 shift[2 * i] = shift[2 * i + 1] = 0;
678
679 fprintf(output, shift);
680 if (op == NULL) {
681 fprintf(output, "Step is NULL\n");
682 return;
683 }
684 switch (op->op) {
685 case XPATH_OP_END:
686 fprintf(output, "END"); break;
687 case XPATH_OP_AND:
688 fprintf(output, "AND"); break;
689 case XPATH_OP_OR:
690 fprintf(output, "OR"); break;
691 case XPATH_OP_EQUAL:
692 if (op->value)
693 fprintf(output, "EQUAL =");
694 else
695 fprintf(output, "EQUAL !=");
696 break;
697 case XPATH_OP_CMP:
698 if (op->value)
699 fprintf(output, "CMP <");
700 else
701 fprintf(output, "CMP >");
702 if (!op->value2)
703 fprintf(output, "=");
704 break;
705 case XPATH_OP_PLUS:
706 if (op->value == 0)
707 fprintf(output, "PLUS -");
708 else if (op->value == 1)
709 fprintf(output, "PLUS +");
710 else if (op->value == 2)
711 fprintf(output, "PLUS unary -");
712 else if (op->value == 3)
713 fprintf(output, "PLUS unary - -");
714 break;
715 case XPATH_OP_MULT:
716 if (op->value == 0)
717 fprintf(output, "MULT *");
718 else if (op->value == 1)
719 fprintf(output, "MULT div");
720 else
721 fprintf(output, "MULT mod");
722 break;
723 case XPATH_OP_UNION:
724 fprintf(output, "UNION"); break;
725 case XPATH_OP_ROOT:
726 fprintf(output, "ROOT"); break;
727 case XPATH_OP_NODE:
728 fprintf(output, "NODE"); break;
729 case XPATH_OP_RESET:
730 fprintf(output, "RESET"); break;
731 case XPATH_OP_SORT:
732 fprintf(output, "SORT"); break;
733 case XPATH_OP_COLLECT: {
734 xmlXPathAxisVal axis = op->value;
735 xmlXPathTestVal test = op->value2;
736 xmlXPathTypeVal type = op->value3;
737 const xmlChar *prefix = op->value4;
738 const xmlChar *name = op->value5;
739
740 fprintf(output, "COLLECT ");
741 switch (axis) {
742 case AXIS_ANCESTOR:
743 fprintf(output, " 'ancestors' "); break;
744 case AXIS_ANCESTOR_OR_SELF:
745 fprintf(output, " 'ancestors-or-self' "); break;
746 case AXIS_ATTRIBUTE:
747 fprintf(output, " 'attributes' "); break;
748 case AXIS_CHILD:
749 fprintf(output, " 'child' "); break;
750 case AXIS_DESCENDANT:
751 fprintf(output, " 'descendant' "); break;
752 case AXIS_DESCENDANT_OR_SELF:
753 fprintf(output, " 'descendant-or-self' "); break;
754 case AXIS_FOLLOWING:
755 fprintf(output, " 'following' "); break;
756 case AXIS_FOLLOWING_SIBLING:
757 fprintf(output, " 'following-siblings' "); break;
758 case AXIS_NAMESPACE:
759 fprintf(output, " 'namespace' "); break;
760 case AXIS_PARENT:
761 fprintf(output, " 'parent' "); break;
762 case AXIS_PRECEDING:
763 fprintf(output, " 'preceding' "); break;
764 case AXIS_PRECEDING_SIBLING:
765 fprintf(output, " 'preceding-sibling' "); break;
766 case AXIS_SELF:
767 fprintf(output, " 'self' "); break;
768 }
769 switch (test) {
770 case NODE_TEST_NONE:
771 fprintf(output, "'none' "); break;
772 case NODE_TEST_TYPE:
773 fprintf(output, "'type' "); break;
774 case NODE_TEST_PI:
775 fprintf(output, "'PI' "); break;
776 case NODE_TEST_ALL:
777 fprintf(output, "'all' "); break;
778 case NODE_TEST_NS:
779 fprintf(output, "'namespace' "); break;
780 case NODE_TEST_NAME:
781 fprintf(output, "'name' "); break;
782 }
783 switch (type) {
784 case NODE_TYPE_NODE:
785 fprintf(output, "'node' "); break;
786 case NODE_TYPE_COMMENT:
787 fprintf(output, "'comment' "); break;
788 case NODE_TYPE_TEXT:
789 fprintf(output, "'text' "); break;
790 case NODE_TYPE_PI:
791 fprintf(output, "'PI' "); break;
792 }
793 if (prefix != NULL)
794 fprintf(output, "%s:", prefix);
795 if (name != NULL)
796 fprintf(output, "%s", name);
797 break;
798
799 }
800 case XPATH_OP_VALUE: {
801 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
802
803 fprintf(output, "ELEM ");
804 xmlXPathDebugDumpObject(output, object, 0);
805 goto finish;
806 }
807 case XPATH_OP_VARIABLE: {
808 const xmlChar *prefix = op->value5;
809 const xmlChar *name = op->value4;
810
811 if (prefix != NULL)
812 fprintf(output, "VARIABLE %s:%s", prefix, name);
813 else
814 fprintf(output, "VARIABLE %s", name);
815 break;
816 }
817 case XPATH_OP_FUNCTION: {
818 int nbargs = op->value;
819 const xmlChar *prefix = op->value5;
820 const xmlChar *name = op->value4;
821
822 if (prefix != NULL)
823 fprintf(output, "FUNCTION %s:%s(%d args)",
824 prefix, name, nbargs);
825 else
826 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
827 break;
828 }
829 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
830 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000831 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +0000832#ifdef LIBXML_XPTR_ENABLED
833 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
834#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000835 default:
836 fprintf(output, "UNKNOWN %d\n", op->op); return;
837 }
838 fprintf(output, "\n");
839finish:
840 if (op->ch1 >= 0)
841 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
842 if (op->ch2 >= 0)
843 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
844}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000845
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000846/**
847 * xmlXPathDebugDumpCompExpr:
848 * @output: the FILE * for the output
849 * @comp: the precompiled XPath expression
850 * @depth: the indentation level.
851 *
852 * Dumps the tree of the compiled XPath expression.
853 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000854void
855xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
856 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000857 int i;
858 char shift[100];
859
860 for (i = 0;((i < depth) && (i < 25));i++)
861 shift[2 * i] = shift[2 * i + 1] = ' ';
862 shift[2 * i] = shift[2 * i + 1] = 0;
863
864 fprintf(output, shift);
865
866 if (comp == NULL) {
867 fprintf(output, "Compiled Expression is NULL\n");
868 return;
869 }
870 fprintf(output, "Compiled Expression : %d elements\n",
871 comp->nbStep);
872 i = comp->last;
873 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
874}
Daniel Veillard017b1082001-06-21 11:20:21 +0000875#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000876
877/************************************************************************
878 * *
879 * Parser stacks related functions and macros *
880 * *
881 ************************************************************************/
882
883/*
884 * Generic function for accessing stacks in the Parser Context
885 */
886
887#define PUSH_AND_POP(type, name) \
888extern int name##Push(xmlXPathParserContextPtr ctxt, type value) { \
889 if (ctxt->name##Nr >= ctxt->name##Max) { \
890 ctxt->name##Max *= 2; \
891 ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab, \
892 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
893 if (ctxt->name##Tab == NULL) { \
894 xmlGenericError(xmlGenericErrorContext, \
895 "realloc failed !\n"); \
896 return(0); \
897 } \
898 } \
899 ctxt->name##Tab[ctxt->name##Nr] = value; \
900 ctxt->name = value; \
901 return(ctxt->name##Nr++); \
902} \
903extern type name##Pop(xmlXPathParserContextPtr ctxt) { \
904 type ret; \
905 if (ctxt->name##Nr <= 0) return(0); \
906 ctxt->name##Nr--; \
907 if (ctxt->name##Nr > 0) \
908 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
909 else \
910 ctxt->name = NULL; \
911 ret = ctxt->name##Tab[ctxt->name##Nr]; \
912 ctxt->name##Tab[ctxt->name##Nr] = 0; \
913 return(ret); \
914} \
915
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000916/**
917 * valuePop:
918 * @ctxt: an XPath evaluation context
919 *
920 * Pops the top XPath object from the value stack
921 *
922 * Returns the XPath object just removed
923 */
924/**
925 * valuePush:
926 * @ctxt: an XPath evaluation context
927 * @value: the XPath object
928 *
929 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000930 *
931 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000932 */
Owen Taylor3473f882001-02-23 17:55:21 +0000933PUSH_AND_POP(xmlXPathObjectPtr, value)
934
Thomas Broyerf06a3d82001-07-16 04:52:57 +0000935/**
936 * xmlXPathPopBoolean:
937 * @ctxt: an XPath parser context
938 *
939 * Pops a boolean from the stack, handling conversion if needed.
940 * Check error with #xmlXPathCheckError.
941 *
942 * Returns the boolean
943 */
944int
945xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
946 xmlXPathObjectPtr obj;
947 int ret;
948
949 obj = valuePop(ctxt);
950 if (obj == NULL) {
951 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
952 return(0);
953 }
954 ret = xmlXPathCastToBoolean(obj);
955 xmlXPathFreeObject(obj);
956 return(ret);
957}
958
959/**
960 * xmlXPathPopNumber:
961 * @ctxt: an XPath parser context
962 *
963 * Pops a number from the stack, handling conversion if needed.
964 * Check error with #xmlXPathCheckError.
965 *
966 * Returns the number
967 */
968double
969xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
970 xmlXPathObjectPtr obj;
971 double ret;
972
973 obj = valuePop(ctxt);
974 if (obj == NULL) {
975 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
976 return(0);
977 }
978 ret = xmlXPathCastToNumber(obj);
979 xmlXPathFreeObject(obj);
980 return(ret);
981}
982
983/**
984 * xmlXPathPopString:
985 * @ctxt: an XPath parser context
986 *
987 * Pops a string from the stack, handling conversion if needed.
988 * Check error with #xmlXPathCheckError.
989 *
990 * Returns the string
991 */
992xmlChar *
993xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
994 xmlXPathObjectPtr obj;
995 xmlChar * ret;
996
997 obj = valuePop(ctxt);
998 if (obj == NULL) {
999 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1000 return(NULL);
1001 }
1002 ret = xmlXPathCastToString(obj);
1003 /* TODO: needs refactoring somewhere else */
1004 if (obj->stringval == ret)
1005 obj->stringval = NULL;
1006 xmlXPathFreeObject(obj);
1007 return(ret);
1008}
1009
1010/**
1011 * xmlXPathPopNodeSet:
1012 * @ctxt: an XPath parser context
1013 *
1014 * Pops a node-set from the stack, handling conversion if needed.
1015 * Check error with #xmlXPathCheckError.
1016 *
1017 * Returns the node-set
1018 */
1019xmlNodeSetPtr
1020xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
1021 xmlXPathObjectPtr obj;
1022 xmlNodeSetPtr ret;
1023
1024 if (ctxt->value == NULL) {
1025 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1026 return(NULL);
1027 }
1028 if (!xmlXPathStackIsNodeSet(ctxt)) {
1029 xmlXPathSetTypeError(ctxt);
1030 return(NULL);
1031 }
1032 obj = valuePop(ctxt);
1033 ret = obj->nodesetval;
1034 xmlXPathFreeNodeSetList(obj);
1035 return(ret);
1036}
1037
1038/**
1039 * xmlXPathPopExternal:
1040 * @ctxt: an XPath parser context
1041 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001042 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001043 * Check error with #xmlXPathCheckError.
1044 *
1045 * Returns the object
1046 */
1047void *
1048xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1049 xmlXPathObjectPtr obj;
1050 void * ret;
1051
1052 if (ctxt->value == NULL) {
1053 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1054 return(NULL);
1055 }
1056 if (ctxt->value->type != XPATH_USERS) {
1057 xmlXPathSetTypeError(ctxt);
1058 return(NULL);
1059 }
1060 obj = valuePop(ctxt);
1061 ret = obj->user;
1062 xmlXPathFreeObject(obj);
1063 return(ret);
1064}
1065
Owen Taylor3473f882001-02-23 17:55:21 +00001066/*
1067 * Macros for accessing the content. Those should be used only by the parser,
1068 * and not exported.
1069 *
1070 * Dirty macros, i.e. one need to make assumption on the context to use them
1071 *
1072 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1073 * CUR returns the current xmlChar value, i.e. a 8 bit value
1074 * in ISO-Latin or UTF-8.
1075 * This should be used internally by the parser
1076 * only to compare to ASCII values otherwise it would break when
1077 * running with UTF-8 encoding.
1078 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1079 * to compare on ASCII based substring.
1080 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1081 * strings within the parser.
1082 * CURRENT Returns the current char value, with the full decoding of
1083 * UTF-8 if we are using this mode. It returns an int.
1084 * NEXT Skip to the next character, this does the proper decoding
1085 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1086 * It returns the pointer to the current xmlChar.
1087 */
1088
1089#define CUR (*ctxt->cur)
1090#define SKIP(val) ctxt->cur += (val)
1091#define NXT(val) ctxt->cur[(val)]
1092#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001093#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1094
1095#define COPY_BUF(l,b,i,v) \
1096 if (l == 1) b[i++] = (xmlChar) v; \
1097 else i += xmlCopyChar(l,&b[i],v)
1098
1099#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001100
1101#define SKIP_BLANKS \
1102 while (IS_BLANK(*(ctxt->cur))) NEXT
1103
1104#define CURRENT (*ctxt->cur)
1105#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1106
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001107
1108#ifndef DBL_DIG
1109#define DBL_DIG 16
1110#endif
1111#ifndef DBL_EPSILON
1112#define DBL_EPSILON 1E-9
1113#endif
1114
1115#define UPPER_DOUBLE 1E9
1116#define LOWER_DOUBLE 1E-5
1117
1118#define INTEGER_DIGITS DBL_DIG
1119#define FRACTION_DIGITS (DBL_DIG + 1)
1120#define EXPONENT_DIGITS (3 + 2)
1121
1122/**
1123 * xmlXPathFormatNumber:
1124 * @number: number to format
1125 * @buffer: output buffer
1126 * @buffersize: size of output buffer
1127 *
1128 * Convert the number into a string representation.
1129 */
1130static void
1131xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1132{
Daniel Veillardcda96922001-08-21 10:56:31 +00001133 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001134 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001135 if (buffersize > (int)sizeof("Infinity"))
1136 sprintf(buffer, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001137 break;
1138 case -1:
1139 if (buffersize > (int)sizeof("-Infinity"))
1140 sprintf(buffer, "-Infinity");
1141 break;
1142 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001143 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001144 if (buffersize > (int)sizeof("NaN"))
1145 sprintf(buffer, "NaN");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001146 } else if (number == ((int) number)) {
1147 char work[30];
1148 char *ptr, *cur;
1149 int res, value = (int) number;
1150
1151 ptr = &buffer[0];
1152 if (value < 0) {
1153 *ptr++ = '-';
1154 value = -value;
1155 }
1156 if (value == 0) {
1157 *ptr++ = '0';
1158 } else {
1159 cur = &work[0];
1160 while (value != 0) {
1161 res = value % 10;
1162 value = value / 10;
1163 *cur++ = '0' + res;
1164 }
1165 cur--;
1166 while ((cur >= &work[0]) && (ptr - buffer < buffersize)) {
1167 *ptr++ = *cur--;
1168 }
1169 }
1170 if (ptr - buffer < buffersize) {
1171 *ptr = 0;
1172 } else if (buffersize > 0) {
1173 ptr--;
1174 *ptr = 0;
1175 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001176 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001177 /* 3 is sign, decimal point, and terminating zero */
1178 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1179 int integer_place, fraction_place;
1180 char *ptr;
1181 char *after_fraction;
1182 double absolute_value;
1183 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001184
Bjorn Reese70a9da52001-04-21 16:57:29 +00001185 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001186
Bjorn Reese70a9da52001-04-21 16:57:29 +00001187 /*
1188 * First choose format - scientific or regular floating point.
1189 * In either case, result is in work, and after_fraction points
1190 * just past the fractional part.
1191 */
1192 if ( ((absolute_value > UPPER_DOUBLE) ||
1193 (absolute_value < LOWER_DOUBLE)) &&
1194 (absolute_value != 0.0) ) {
1195 /* Use scientific notation */
1196 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1197 fraction_place = DBL_DIG - 1;
1198 snprintf(work, sizeof(work),"%*.*e",
1199 integer_place, fraction_place, number);
1200 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001201 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001202 else {
1203 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001204 if (absolute_value > 0.0)
1205 integer_place = 1 + (int)log10(absolute_value);
1206 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001207 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001208 fraction_place = (integer_place > 0)
1209 ? DBL_DIG - integer_place
1210 : DBL_DIG;
1211 size = snprintf(work, sizeof(work), "%0.*f",
1212 fraction_place, number);
1213 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001214 }
1215
Bjorn Reese70a9da52001-04-21 16:57:29 +00001216 /* Remove fractional trailing zeroes */
1217 ptr = after_fraction;
1218 while (*(--ptr) == '0')
1219 ;
1220 if (*ptr != '.')
1221 ptr++;
1222 strcpy(ptr, after_fraction);
1223
1224 /* Finally copy result back to caller */
1225 size = strlen(work) + 1;
1226 if (size > buffersize) {
1227 work[buffersize - 1] = 0;
1228 size = buffersize;
1229 }
1230 memcpy(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001231 }
1232 break;
1233 }
1234}
1235
Owen Taylor3473f882001-02-23 17:55:21 +00001236/************************************************************************
1237 * *
1238 * Error handling routines *
1239 * *
1240 ************************************************************************/
1241
1242
Daniel Veillardb44025c2001-10-11 22:55:55 +00001243static const char *xmlXPathErrorMessages[] = {
Owen Taylor3473f882001-02-23 17:55:21 +00001244 "Ok",
1245 "Number encoding",
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001246 "Unfinished literal",
1247 "Start of literal",
Owen Taylor3473f882001-02-23 17:55:21 +00001248 "Expected $ for variable reference",
1249 "Undefined variable",
1250 "Invalid predicate",
1251 "Invalid expression",
1252 "Missing closing curly brace",
1253 "Unregistered function",
1254 "Invalid operand",
1255 "Invalid type",
1256 "Invalid number of arguments",
1257 "Invalid context size",
1258 "Invalid context position",
1259 "Memory allocation error",
1260 "Syntax error",
1261 "Resource error",
1262 "Sub resource error",
Daniel Veillard61d80a22001-04-27 17:13:01 +00001263 "Undefined namespace prefix",
1264 "Encoding error",
1265 "Char out of XML range"
Owen Taylor3473f882001-02-23 17:55:21 +00001266};
1267
1268/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001269 * xmlXPatherror:
Owen Taylor3473f882001-02-23 17:55:21 +00001270 * @ctxt: the XPath Parser context
1271 * @file: the file name
1272 * @line: the line number
1273 * @no: the error number
1274 *
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001275 * Formats an error message.
Owen Taylor3473f882001-02-23 17:55:21 +00001276 */
1277void
1278xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file,
1279 int line, int no) {
1280 int n;
1281 const xmlChar *cur;
1282 const xmlChar *base;
1283
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001284/* xmlGenericError(xmlGenericErrorContext,
Owen Taylor3473f882001-02-23 17:55:21 +00001285 "Error %s:%d: %s\n", file, line,
1286 xmlXPathErrorMessages[no]);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001287*/
1288 xmlGenericError(xmlGenericErrorContext,
1289 "Error %s\n", xmlXPathErrorMessages[no]);
Owen Taylor3473f882001-02-23 17:55:21 +00001290
1291 cur = ctxt->cur;
1292 base = ctxt->base;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001293 if ((cur == NULL) || (base == NULL))
1294 return;
1295
Owen Taylor3473f882001-02-23 17:55:21 +00001296 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
1297 cur--;
1298 }
1299 n = 0;
1300 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
1301 cur--;
1302 if ((*cur == '\n') || (*cur == '\r')) cur++;
1303 base = cur;
1304 n = 0;
1305 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
1306 xmlGenericError(xmlGenericErrorContext, "%c", (unsigned char) *cur++);
1307 n++;
1308 }
1309 xmlGenericError(xmlGenericErrorContext, "\n");
1310 cur = ctxt->cur;
1311 while ((*cur == '\n') || (*cur == '\r'))
1312 cur--;
1313 n = 0;
1314 while ((cur != base) && (n++ < 80)) {
1315 xmlGenericError(xmlGenericErrorContext, " ");
1316 base++;
1317 }
1318 xmlGenericError(xmlGenericErrorContext,"^\n");
1319}
1320
1321
1322/************************************************************************
1323 * *
1324 * Routines to handle NodeSets *
1325 * *
1326 ************************************************************************/
1327
1328/**
1329 * xmlXPathCmpNodes:
1330 * @node1: the first node
1331 * @node2: the second node
1332 *
1333 * Compare two nodes w.r.t document order
1334 *
1335 * Returns -2 in case of error 1 if first point < second point, 0 if
1336 * that's the same node, -1 otherwise
1337 */
1338int
1339xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1340 int depth1, depth2;
1341 xmlNodePtr cur, root;
1342
1343 if ((node1 == NULL) || (node2 == NULL))
1344 return(-2);
1345 /*
1346 * a couple of optimizations which will avoid computations in most cases
1347 */
1348 if (node1 == node2)
1349 return(0);
Daniel Veillardb33c2012001-04-25 12:59:04 +00001350 if ((node1->type == XML_NAMESPACE_DECL) ||
1351 (node2->type == XML_NAMESPACE_DECL))
1352 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001353 if (node1 == node2->prev)
1354 return(1);
1355 if (node1 == node2->next)
1356 return(-1);
1357
1358 /*
1359 * compute depth to root
1360 */
1361 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1362 if (cur == node1)
1363 return(1);
1364 depth2++;
1365 }
1366 root = cur;
1367 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1368 if (cur == node2)
1369 return(-1);
1370 depth1++;
1371 }
1372 /*
1373 * Distinct document (or distinct entities :-( ) case.
1374 */
1375 if (root != cur) {
1376 return(-2);
1377 }
1378 /*
1379 * get the nearest common ancestor.
1380 */
1381 while (depth1 > depth2) {
1382 depth1--;
1383 node1 = node1->parent;
1384 }
1385 while (depth2 > depth1) {
1386 depth2--;
1387 node2 = node2->parent;
1388 }
1389 while (node1->parent != node2->parent) {
1390 node1 = node1->parent;
1391 node2 = node2->parent;
1392 /* should not happen but just in case ... */
1393 if ((node1 == NULL) || (node2 == NULL))
1394 return(-2);
1395 }
1396 /*
1397 * Find who's first.
1398 */
1399 if (node1 == node2->next)
1400 return(-1);
1401 for (cur = node1->next;cur != NULL;cur = cur->next)
1402 if (cur == node2)
1403 return(1);
1404 return(-1); /* assume there is no sibling list corruption */
1405}
1406
1407/**
1408 * xmlXPathNodeSetSort:
1409 * @set: the node set
1410 *
1411 * Sort the node set in document order
1412 */
1413void
1414xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001415 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001416 xmlNodePtr tmp;
1417
1418 if (set == NULL)
1419 return;
1420
1421 /* Use Shell's sort to sort the node-set */
1422 len = set->nodeNr;
1423 for (incr = len / 2; incr > 0; incr /= 2) {
1424 for (i = incr; i < len; i++) {
1425 j = i - incr;
1426 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001427 if (xmlXPathCmpNodes(set->nodeTab[j],
1428 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001429 tmp = set->nodeTab[j];
1430 set->nodeTab[j] = set->nodeTab[j + incr];
1431 set->nodeTab[j + incr] = tmp;
1432 j -= incr;
1433 } else
1434 break;
1435 }
1436 }
1437 }
1438}
1439
1440#define XML_NODESET_DEFAULT 10
1441/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001442 * xmlXPathNodeSetDupNs:
1443 * @node: the parent node of the namespace XPath node
1444 * @ns: the libxml namespace declaration node.
1445 *
1446 * Namespace node in libxml don't match the XPath semantic. In a node set
1447 * the namespace nodes are duplicated and the next pointer is set to the
1448 * parent node in the XPath semantic.
1449 *
1450 * Returns the newly created object.
1451 */
1452static xmlNodePtr
1453xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
1454 xmlNsPtr cur;
1455
1456 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1457 return(NULL);
1458 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
1459 return((xmlNodePtr) ns);
1460
1461 /*
1462 * Allocate a new Namespace and fill the fields.
1463 */
1464 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1465 if (cur == NULL) {
1466 xmlGenericError(xmlGenericErrorContext,
1467 "xmlXPathNodeSetDupNs : malloc failed\n");
1468 return(NULL);
1469 }
1470 memset(cur, 0, sizeof(xmlNs));
1471 cur->type = XML_NAMESPACE_DECL;
1472 if (ns->href != NULL)
1473 cur->href = xmlStrdup(ns->href);
1474 if (ns->prefix != NULL)
1475 cur->prefix = xmlStrdup(ns->prefix);
1476 cur->next = (xmlNsPtr) node;
1477 return((xmlNodePtr) cur);
1478}
1479
1480/**
1481 * xmlXPathNodeSetFreeNs:
1482 * @ns: the XPath namespace node found in a nodeset.
1483 *
1484 * Namespace node in libxml don't match the XPath semantic. In a node set
1485 * the namespace nodes are duplicated and the next pointer is set to the
1486 * parent node in the XPath semantic. Check if such a node need to be freed
1487 */
1488static void
1489xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
1490 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1491 return;
1492
1493 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
1494 if (ns->href != NULL)
1495 xmlFree((xmlChar *)ns->href);
1496 if (ns->prefix != NULL)
1497 xmlFree((xmlChar *)ns->prefix);
1498 xmlFree(ns);
1499 }
1500}
1501
1502/**
Owen Taylor3473f882001-02-23 17:55:21 +00001503 * xmlXPathNodeSetCreate:
1504 * @val: an initial xmlNodePtr, or NULL
1505 *
1506 * Create a new xmlNodeSetPtr of type double and of value @val
1507 *
1508 * Returns the newly created object.
1509 */
1510xmlNodeSetPtr
1511xmlXPathNodeSetCreate(xmlNodePtr val) {
1512 xmlNodeSetPtr ret;
1513
1514 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1515 if (ret == NULL) {
1516 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001517 "xmlXPathNodeSetCreate: out of memory\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001518 return(NULL);
1519 }
1520 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1521 if (val != NULL) {
1522 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1523 sizeof(xmlNodePtr));
1524 if (ret->nodeTab == NULL) {
1525 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001526 "xmlXPathNodeSetCreate: out of memory\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001527 return(NULL);
1528 }
1529 memset(ret->nodeTab, 0 ,
1530 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1531 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001532 if (val->type == XML_NAMESPACE_DECL) {
1533 xmlNsPtr ns = (xmlNsPtr) val;
1534
1535 ret->nodeTab[ret->nodeNr++] =
1536 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1537 } else
1538 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001539 }
1540 return(ret);
1541}
1542
1543/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001544 * xmlXPathNodeSetContains:
1545 * @cur: the node-set
1546 * @val: the node
1547 *
1548 * checks whether @cur contains @val
1549 *
1550 * Returns true (1) if @cur contains @val, false (0) otherwise
1551 */
1552int
1553xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1554 int i;
1555
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001556 if (val->type == XML_NAMESPACE_DECL) {
1557 for (i = 0; i < cur->nodeNr; i++) {
1558 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1559 xmlNsPtr ns1, ns2;
1560
1561 ns1 = (xmlNsPtr) val;
1562 ns2 = (xmlNsPtr) cur->nodeTab[i];
1563 if (ns1 == ns2)
1564 return(1);
1565 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
1566 (xmlStrEqual(ns1->prefix, ns2->prefix)))
1567 return(1);
1568 }
1569 }
1570 } else {
1571 for (i = 0; i < cur->nodeNr; i++) {
1572 if (cur->nodeTab[i] == val)
1573 return(1);
1574 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001575 }
1576 return(0);
1577}
1578
1579/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001580 * xmlXPathNodeSetAddNs:
1581 * @cur: the initial node set
1582 * @node: the hosting node
1583 * @ns: a the namespace node
1584 *
1585 * add a new namespace node to an existing NodeSet
1586 */
1587static void
1588xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
1589 int i;
1590
1591 if ((ns == NULL) || (node == NULL) || (ns->type != XML_NAMESPACE_DECL) ||
1592 (node->type != XML_ELEMENT_NODE))
1593 return;
1594
1595 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1596 /*
1597 * check against doublons
1598 */
1599 for (i = 0;i < cur->nodeNr;i++) {
1600 if ((cur->nodeTab[i] != NULL) &&
1601 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00001602 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001603 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
1604 return;
1605 }
1606
1607 /*
1608 * grow the nodeTab if needed
1609 */
1610 if (cur->nodeMax == 0) {
1611 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1612 sizeof(xmlNodePtr));
1613 if (cur->nodeTab == NULL) {
1614 xmlGenericError(xmlGenericErrorContext,
1615 "xmlXPathNodeSetAdd: out of memory\n");
1616 return;
1617 }
1618 memset(cur->nodeTab, 0 ,
1619 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1620 cur->nodeMax = XML_NODESET_DEFAULT;
1621 } else if (cur->nodeNr == cur->nodeMax) {
1622 xmlNodePtr *temp;
1623
1624 cur->nodeMax *= 2;
1625 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1626 sizeof(xmlNodePtr));
1627 if (temp == NULL) {
1628 xmlGenericError(xmlGenericErrorContext,
1629 "xmlXPathNodeSetAdd: out of memory\n");
1630 return;
1631 }
1632 cur->nodeTab = temp;
1633 }
1634 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
1635}
1636
1637/**
Owen Taylor3473f882001-02-23 17:55:21 +00001638 * xmlXPathNodeSetAdd:
1639 * @cur: the initial node set
1640 * @val: a new xmlNodePtr
1641 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001642 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00001643 */
1644void
1645xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1646 int i;
1647
1648 if (val == NULL) return;
1649
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001650 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001651 /*
1652 * check against doublons
1653 */
1654 for (i = 0;i < cur->nodeNr;i++)
1655 if (cur->nodeTab[i] == val) return;
1656
1657 /*
1658 * grow the nodeTab if needed
1659 */
1660 if (cur->nodeMax == 0) {
1661 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1662 sizeof(xmlNodePtr));
1663 if (cur->nodeTab == NULL) {
1664 xmlGenericError(xmlGenericErrorContext,
1665 "xmlXPathNodeSetAdd: out of memory\n");
1666 return;
1667 }
1668 memset(cur->nodeTab, 0 ,
1669 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1670 cur->nodeMax = XML_NODESET_DEFAULT;
1671 } else if (cur->nodeNr == cur->nodeMax) {
1672 xmlNodePtr *temp;
1673
1674 cur->nodeMax *= 2;
1675 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1676 sizeof(xmlNodePtr));
1677 if (temp == NULL) {
1678 xmlGenericError(xmlGenericErrorContext,
1679 "xmlXPathNodeSetAdd: out of memory\n");
1680 return;
1681 }
1682 cur->nodeTab = temp;
1683 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001684 if (val->type == XML_NAMESPACE_DECL) {
1685 xmlNsPtr ns = (xmlNsPtr) val;
1686
1687 cur->nodeTab[cur->nodeNr++] =
1688 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1689 } else
1690 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001691}
1692
1693/**
1694 * xmlXPathNodeSetAddUnique:
1695 * @cur: the initial node set
1696 * @val: a new xmlNodePtr
1697 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001698 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00001699 * when we are sure the node is not already in the set.
1700 */
1701void
1702xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1703 if (val == NULL) return;
1704
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001705 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001706 /*
1707 * grow the nodeTab if needed
1708 */
1709 if (cur->nodeMax == 0) {
1710 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1711 sizeof(xmlNodePtr));
1712 if (cur->nodeTab == NULL) {
1713 xmlGenericError(xmlGenericErrorContext,
1714 "xmlXPathNodeSetAddUnique: out of memory\n");
1715 return;
1716 }
1717 memset(cur->nodeTab, 0 ,
1718 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1719 cur->nodeMax = XML_NODESET_DEFAULT;
1720 } else if (cur->nodeNr == cur->nodeMax) {
1721 xmlNodePtr *temp;
1722
1723 cur->nodeMax *= 2;
1724 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1725 sizeof(xmlNodePtr));
1726 if (temp == NULL) {
1727 xmlGenericError(xmlGenericErrorContext,
1728 "xmlXPathNodeSetAddUnique: out of memory\n");
1729 return;
1730 }
1731 cur->nodeTab = temp;
1732 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001733 if (val->type == XML_NAMESPACE_DECL) {
1734 xmlNsPtr ns = (xmlNsPtr) val;
1735
1736 cur->nodeTab[cur->nodeNr++] =
1737 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1738 } else
1739 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001740}
1741
1742/**
1743 * xmlXPathNodeSetMerge:
1744 * @val1: the first NodeSet or NULL
1745 * @val2: the second NodeSet
1746 *
1747 * Merges two nodesets, all nodes from @val2 are added to @val1
1748 * if @val1 is NULL, a new set is created and copied from @val2
1749 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001750 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00001751 */
1752xmlNodeSetPtr
1753xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001754 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001755
1756 if (val2 == NULL) return(val1);
1757 if (val1 == NULL) {
1758 val1 = xmlXPathNodeSetCreate(NULL);
1759 }
1760
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001761 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001762 initNr = val1->nodeNr;
1763
1764 for (i = 0;i < val2->nodeNr;i++) {
1765 /*
1766 * check against doublons
1767 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001768 skip = 0;
1769 for (j = 0; j < initNr; j++) {
1770 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1771 skip = 1;
1772 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001773 } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) &&
1774 (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) {
1775 xmlNsPtr ns1, ns2;
1776 ns1 = (xmlNsPtr) val1->nodeTab[j];
1777 ns2 = (xmlNsPtr) val2->nodeTab[i];
1778 if ((ns1->next == ns2->next) &&
1779 (xmlStrEqual(ns1->prefix, ns2->prefix))) {
1780 skip = 1;
1781 break;
1782 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001783 }
1784 }
1785 if (skip)
1786 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00001787
1788 /*
1789 * grow the nodeTab if needed
1790 */
1791 if (val1->nodeMax == 0) {
1792 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1793 sizeof(xmlNodePtr));
1794 if (val1->nodeTab == NULL) {
1795 xmlGenericError(xmlGenericErrorContext,
1796 "xmlXPathNodeSetMerge: out of memory\n");
1797 return(NULL);
1798 }
1799 memset(val1->nodeTab, 0 ,
1800 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1801 val1->nodeMax = XML_NODESET_DEFAULT;
1802 } else if (val1->nodeNr == val1->nodeMax) {
1803 xmlNodePtr *temp;
1804
1805 val1->nodeMax *= 2;
1806 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1807 sizeof(xmlNodePtr));
1808 if (temp == NULL) {
1809 xmlGenericError(xmlGenericErrorContext,
1810 "xmlXPathNodeSetMerge: out of memory\n");
1811 return(NULL);
1812 }
1813 val1->nodeTab = temp;
1814 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001815 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1816 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1817
1818 val1->nodeTab[val1->nodeNr++] =
1819 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1820 } else
1821 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00001822 }
1823
1824 return(val1);
1825}
1826
1827/**
Daniel Veillard75be0132002-03-13 10:03:35 +00001828 * xmlXPathNodeSetMergeUnique:
1829 * @val1: the first NodeSet or NULL
1830 * @val2: the second NodeSet
1831 *
1832 * Merges two nodesets, all nodes from @val2 are added to @val1
1833 * if @val1 is NULL, a new set is created and copied from @val2
1834 *
1835 * Returns @val1 once extended or NULL in case of error.
1836 */
1837static xmlNodeSetPtr
1838xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
1839 int i, initNr;
1840
1841 if (val2 == NULL) return(val1);
1842 if (val1 == NULL) {
1843 val1 = xmlXPathNodeSetCreate(NULL);
1844 }
1845
1846 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1847 initNr = val1->nodeNr;
1848
1849 for (i = 0;i < val2->nodeNr;i++) {
1850 /*
1851 * grow the nodeTab if needed
1852 */
1853 if (val1->nodeMax == 0) {
1854 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1855 sizeof(xmlNodePtr));
1856 if (val1->nodeTab == NULL) {
1857 xmlGenericError(xmlGenericErrorContext,
1858 "xmlXPathNodeSetMerge: out of memory\n");
1859 return(NULL);
1860 }
1861 memset(val1->nodeTab, 0 ,
1862 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1863 val1->nodeMax = XML_NODESET_DEFAULT;
1864 } else if (val1->nodeNr == val1->nodeMax) {
1865 xmlNodePtr *temp;
1866
1867 val1->nodeMax *= 2;
1868 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1869 sizeof(xmlNodePtr));
1870 if (temp == NULL) {
1871 xmlGenericError(xmlGenericErrorContext,
1872 "xmlXPathNodeSetMerge: out of memory\n");
1873 return(NULL);
1874 }
1875 val1->nodeTab = temp;
1876 }
1877 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1878 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1879
1880 val1->nodeTab[val1->nodeNr++] =
1881 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1882 } else
1883 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
1884 }
1885
1886 return(val1);
1887}
1888
1889/**
Owen Taylor3473f882001-02-23 17:55:21 +00001890 * xmlXPathNodeSetDel:
1891 * @cur: the initial node set
1892 * @val: an xmlNodePtr
1893 *
1894 * Removes an xmlNodePtr from an existing NodeSet
1895 */
1896void
1897xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
1898 int i;
1899
1900 if (cur == NULL) return;
1901 if (val == NULL) return;
1902
1903 /*
1904 * check against doublons
1905 */
1906 for (i = 0;i < cur->nodeNr;i++)
1907 if (cur->nodeTab[i] == val) break;
1908
1909 if (i >= cur->nodeNr) {
1910#ifdef DEBUG
1911 xmlGenericError(xmlGenericErrorContext,
1912 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
1913 val->name);
1914#endif
1915 return;
1916 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001917 if ((cur->nodeTab[i] != NULL) &&
1918 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
1919 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001920 cur->nodeNr--;
1921 for (;i < cur->nodeNr;i++)
1922 cur->nodeTab[i] = cur->nodeTab[i + 1];
1923 cur->nodeTab[cur->nodeNr] = NULL;
1924}
1925
1926/**
1927 * xmlXPathNodeSetRemove:
1928 * @cur: the initial node set
1929 * @val: the index to remove
1930 *
1931 * Removes an entry from an existing NodeSet list.
1932 */
1933void
1934xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
1935 if (cur == NULL) return;
1936 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001937 if ((cur->nodeTab[val] != NULL) &&
1938 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
1939 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00001940 cur->nodeNr--;
1941 for (;val < cur->nodeNr;val++)
1942 cur->nodeTab[val] = cur->nodeTab[val + 1];
1943 cur->nodeTab[cur->nodeNr] = NULL;
1944}
1945
1946/**
1947 * xmlXPathFreeNodeSet:
1948 * @obj: the xmlNodeSetPtr to free
1949 *
1950 * Free the NodeSet compound (not the actual nodes !).
1951 */
1952void
1953xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
1954 if (obj == NULL) return;
1955 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001956 int i;
1957
1958 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1959 for (i = 0;i < obj->nodeNr;i++)
1960 if ((obj->nodeTab[i] != NULL) &&
1961 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
1962 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001963 xmlFree(obj->nodeTab);
1964 }
Owen Taylor3473f882001-02-23 17:55:21 +00001965 xmlFree(obj);
1966}
1967
1968/**
1969 * xmlXPathFreeValueTree:
1970 * @obj: the xmlNodeSetPtr to free
1971 *
1972 * Free the NodeSet compound and the actual tree, this is different
1973 * from xmlXPathFreeNodeSet()
1974 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001975static void
Owen Taylor3473f882001-02-23 17:55:21 +00001976xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
1977 int i;
1978
1979 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001980
1981 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001982 for (i = 0;i < obj->nodeNr;i++) {
1983 if (obj->nodeTab[i] != NULL) {
1984 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1985 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
1986 } else {
1987 xmlFreeNodeList(obj->nodeTab[i]);
1988 }
1989 }
1990 }
Owen Taylor3473f882001-02-23 17:55:21 +00001991 xmlFree(obj->nodeTab);
1992 }
Owen Taylor3473f882001-02-23 17:55:21 +00001993 xmlFree(obj);
1994}
1995
1996#if defined(DEBUG) || defined(DEBUG_STEP)
1997/**
1998 * xmlGenericErrorContextNodeSet:
1999 * @output: a FILE * for the output
2000 * @obj: the xmlNodeSetPtr to free
2001 *
2002 * Quick display of a NodeSet
2003 */
2004void
2005xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
2006 int i;
2007
2008 if (output == NULL) output = xmlGenericErrorContext;
2009 if (obj == NULL) {
2010 fprintf(output, "NodeSet == NULL !\n");
2011 return;
2012 }
2013 if (obj->nodeNr == 0) {
2014 fprintf(output, "NodeSet is empty\n");
2015 return;
2016 }
2017 if (obj->nodeTab == NULL) {
2018 fprintf(output, " nodeTab == NULL !\n");
2019 return;
2020 }
2021 for (i = 0; i < obj->nodeNr; i++) {
2022 if (obj->nodeTab[i] == NULL) {
2023 fprintf(output, " NULL !\n");
2024 return;
2025 }
2026 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
2027 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
2028 fprintf(output, " /");
2029 else if (obj->nodeTab[i]->name == NULL)
2030 fprintf(output, " noname!");
2031 else fprintf(output, " %s", obj->nodeTab[i]->name);
2032 }
2033 fprintf(output, "\n");
2034}
2035#endif
2036
2037/**
2038 * xmlXPathNewNodeSet:
2039 * @val: the NodePtr value
2040 *
2041 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2042 * it with the single Node @val
2043 *
2044 * Returns the newly created object.
2045 */
2046xmlXPathObjectPtr
2047xmlXPathNewNodeSet(xmlNodePtr val) {
2048 xmlXPathObjectPtr ret;
2049
2050 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2051 if (ret == NULL) {
2052 xmlGenericError(xmlGenericErrorContext,
2053 "xmlXPathNewNodeSet: out of memory\n");
2054 return(NULL);
2055 }
2056 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2057 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00002058 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002059 ret->nodesetval = xmlXPathNodeSetCreate(val);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002060 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002061 return(ret);
2062}
2063
2064/**
2065 * xmlXPathNewValueTree:
2066 * @val: the NodePtr value
2067 *
2068 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
2069 * it with the tree root @val
2070 *
2071 * Returns the newly created object.
2072 */
2073xmlXPathObjectPtr
2074xmlXPathNewValueTree(xmlNodePtr val) {
2075 xmlXPathObjectPtr ret;
2076
2077 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2078 if (ret == NULL) {
2079 xmlGenericError(xmlGenericErrorContext,
2080 "xmlXPathNewNodeSet: out of memory\n");
2081 return(NULL);
2082 }
2083 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2084 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002085 ret->boolval = 1;
2086 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00002087 ret->nodesetval = xmlXPathNodeSetCreate(val);
2088 return(ret);
2089}
2090
2091/**
2092 * xmlXPathNewNodeSetList:
2093 * @val: an existing NodeSet
2094 *
2095 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2096 * it with the Nodeset @val
2097 *
2098 * Returns the newly created object.
2099 */
2100xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002101xmlXPathNewNodeSetList(xmlNodeSetPtr val)
2102{
Owen Taylor3473f882001-02-23 17:55:21 +00002103 xmlXPathObjectPtr ret;
2104 int i;
2105
2106 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002107 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002108 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002109 ret = xmlXPathNewNodeSet(NULL);
2110 else {
2111 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
2112 for (i = 1; i < val->nodeNr; ++i)
2113 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2114 }
Owen Taylor3473f882001-02-23 17:55:21 +00002115
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002116 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002117}
2118
2119/**
2120 * xmlXPathWrapNodeSet:
2121 * @val: the NodePtr value
2122 *
2123 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2124 *
2125 * Returns the newly created object.
2126 */
2127xmlXPathObjectPtr
2128xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2129 xmlXPathObjectPtr ret;
2130
2131 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2132 if (ret == NULL) {
2133 xmlGenericError(xmlGenericErrorContext,
2134 "xmlXPathWrapNodeSet: out of memory\n");
2135 return(NULL);
2136 }
2137 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2138 ret->type = XPATH_NODESET;
2139 ret->nodesetval = val;
2140 return(ret);
2141}
2142
2143/**
2144 * xmlXPathFreeNodeSetList:
2145 * @obj: an existing NodeSetList object
2146 *
2147 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2148 * the list contrary to xmlXPathFreeObject().
2149 */
2150void
2151xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2152 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002153 xmlFree(obj);
2154}
2155
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002156/**
2157 * xmlXPathDifference:
2158 * @nodes1: a node-set
2159 * @nodes2: a node-set
2160 *
2161 * Implements the EXSLT - Sets difference() function:
2162 * node-set set:difference (node-set, node-set)
2163 *
2164 * Returns the difference between the two node sets, or nodes1 if
2165 * nodes2 is empty
2166 */
2167xmlNodeSetPtr
2168xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2169 xmlNodeSetPtr ret;
2170 int i, l1;
2171 xmlNodePtr cur;
2172
2173 if (xmlXPathNodeSetIsEmpty(nodes2))
2174 return(nodes1);
2175
2176 ret = xmlXPathNodeSetCreate(NULL);
2177 if (xmlXPathNodeSetIsEmpty(nodes1))
2178 return(ret);
2179
2180 l1 = xmlXPathNodeSetGetLength(nodes1);
2181
2182 for (i = 0; i < l1; i++) {
2183 cur = xmlXPathNodeSetItem(nodes1, i);
2184 if (!xmlXPathNodeSetContains(nodes2, cur))
2185 xmlXPathNodeSetAddUnique(ret, cur);
2186 }
2187 return(ret);
2188}
2189
2190/**
2191 * xmlXPathIntersection:
2192 * @nodes1: a node-set
2193 * @nodes2: a node-set
2194 *
2195 * Implements the EXSLT - Sets intersection() function:
2196 * node-set set:intersection (node-set, node-set)
2197 *
2198 * Returns a node set comprising the nodes that are within both the
2199 * node sets passed as arguments
2200 */
2201xmlNodeSetPtr
2202xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2203 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2204 int i, l1;
2205 xmlNodePtr cur;
2206
2207 if (xmlXPathNodeSetIsEmpty(nodes1))
2208 return(ret);
2209 if (xmlXPathNodeSetIsEmpty(nodes2))
2210 return(ret);
2211
2212 l1 = xmlXPathNodeSetGetLength(nodes1);
2213
2214 for (i = 0; i < l1; i++) {
2215 cur = xmlXPathNodeSetItem(nodes1, i);
2216 if (xmlXPathNodeSetContains(nodes2, cur))
2217 xmlXPathNodeSetAddUnique(ret, cur);
2218 }
2219 return(ret);
2220}
2221
2222/**
2223 * xmlXPathDistinctSorted:
2224 * @nodes: a node-set, sorted by document order
2225 *
2226 * Implements the EXSLT - Sets distinct() function:
2227 * node-set set:distinct (node-set)
2228 *
2229 * Returns a subset of the nodes contained in @nodes, or @nodes if
2230 * it is empty
2231 */
2232xmlNodeSetPtr
2233xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2234 xmlNodeSetPtr ret;
2235 xmlHashTablePtr hash;
2236 int i, l;
2237 xmlChar * strval;
2238 xmlNodePtr cur;
2239
2240 if (xmlXPathNodeSetIsEmpty(nodes))
2241 return(nodes);
2242
2243 ret = xmlXPathNodeSetCreate(NULL);
2244 l = xmlXPathNodeSetGetLength(nodes);
2245 hash = xmlHashCreate (l);
2246 for (i = 0; i < l; i++) {
2247 cur = xmlXPathNodeSetItem(nodes, i);
2248 strval = xmlXPathCastNodeToString(cur);
2249 if (xmlHashLookup(hash, strval) == NULL) {
2250 xmlHashAddEntry(hash, strval, strval);
2251 xmlXPathNodeSetAddUnique(ret, cur);
2252 } else {
2253 xmlFree(strval);
2254 }
2255 }
2256 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2257 return(ret);
2258}
2259
2260/**
2261 * xmlXPathDistinct:
2262 * @nodes: a node-set
2263 *
2264 * Implements the EXSLT - Sets distinct() function:
2265 * node-set set:distinct (node-set)
2266 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2267 * is called with the sorted node-set
2268 *
2269 * Returns a subset of the nodes contained in @nodes, or @nodes if
2270 * it is empty
2271 */
2272xmlNodeSetPtr
2273xmlXPathDistinct (xmlNodeSetPtr nodes) {
2274 if (xmlXPathNodeSetIsEmpty(nodes))
2275 return(nodes);
2276
2277 xmlXPathNodeSetSort(nodes);
2278 return(xmlXPathDistinctSorted(nodes));
2279}
2280
2281/**
2282 * xmlXPathHasSameNodes:
2283 * @nodes1: a node-set
2284 * @nodes2: a node-set
2285 *
2286 * Implements the EXSLT - Sets has-same-nodes function:
2287 * boolean set:has-same-node(node-set, node-set)
2288 *
2289 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2290 * otherwise
2291 */
2292int
2293xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2294 int i, l;
2295 xmlNodePtr cur;
2296
2297 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2298 xmlXPathNodeSetIsEmpty(nodes2))
2299 return(0);
2300
2301 l = xmlXPathNodeSetGetLength(nodes1);
2302 for (i = 0; i < l; i++) {
2303 cur = xmlXPathNodeSetItem(nodes1, i);
2304 if (xmlXPathNodeSetContains(nodes2, cur))
2305 return(1);
2306 }
2307 return(0);
2308}
2309
2310/**
2311 * xmlXPathNodeLeadingSorted:
2312 * @nodes: a node-set, sorted by document order
2313 * @node: a node
2314 *
2315 * Implements the EXSLT - Sets leading() function:
2316 * node-set set:leading (node-set, node-set)
2317 *
2318 * Returns the nodes in @nodes that precede @node in document order,
2319 * @nodes if @node is NULL or an empty node-set if @nodes
2320 * doesn't contain @node
2321 */
2322xmlNodeSetPtr
2323xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2324 int i, l;
2325 xmlNodePtr cur;
2326 xmlNodeSetPtr ret;
2327
2328 if (node == NULL)
2329 return(nodes);
2330
2331 ret = xmlXPathNodeSetCreate(NULL);
2332 if (xmlXPathNodeSetIsEmpty(nodes) ||
2333 (!xmlXPathNodeSetContains(nodes, node)))
2334 return(ret);
2335
2336 l = xmlXPathNodeSetGetLength(nodes);
2337 for (i = 0; i < l; i++) {
2338 cur = xmlXPathNodeSetItem(nodes, i);
2339 if (cur == node)
2340 break;
2341 xmlXPathNodeSetAddUnique(ret, cur);
2342 }
2343 return(ret);
2344}
2345
2346/**
2347 * xmlXPathNodeLeading:
2348 * @nodes: a node-set
2349 * @node: a node
2350 *
2351 * Implements the EXSLT - Sets leading() function:
2352 * node-set set:leading (node-set, node-set)
2353 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2354 * is called.
2355 *
2356 * Returns the nodes in @nodes that precede @node in document order,
2357 * @nodes if @node is NULL or an empty node-set if @nodes
2358 * doesn't contain @node
2359 */
2360xmlNodeSetPtr
2361xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2362 xmlXPathNodeSetSort(nodes);
2363 return(xmlXPathNodeLeadingSorted(nodes, node));
2364}
2365
2366/**
2367 * xmlXPathLeadingSorted:
2368 * @nodes1: a node-set, sorted by document order
2369 * @nodes2: a node-set, sorted by document order
2370 *
2371 * Implements the EXSLT - Sets leading() function:
2372 * node-set set:leading (node-set, node-set)
2373 *
2374 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2375 * in document order, @nodes1 if @nodes2 is NULL or empty or
2376 * an empty node-set if @nodes1 doesn't contain @nodes2
2377 */
2378xmlNodeSetPtr
2379xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2380 if (xmlXPathNodeSetIsEmpty(nodes2))
2381 return(nodes1);
2382 return(xmlXPathNodeLeadingSorted(nodes1,
2383 xmlXPathNodeSetItem(nodes2, 1)));
2384}
2385
2386/**
2387 * xmlXPathLeading:
2388 * @nodes1: a node-set
2389 * @nodes2: a node-set
2390 *
2391 * Implements the EXSLT - Sets leading() function:
2392 * node-set set:leading (node-set, node-set)
2393 * @nodes1 and @nodes2 are sorted by document order, then
2394 * #exslSetsLeadingSorted is called.
2395 *
2396 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2397 * in document order, @nodes1 if @nodes2 is NULL or empty or
2398 * an empty node-set if @nodes1 doesn't contain @nodes2
2399 */
2400xmlNodeSetPtr
2401xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2402 if (xmlXPathNodeSetIsEmpty(nodes2))
2403 return(nodes1);
2404 if (xmlXPathNodeSetIsEmpty(nodes1))
2405 return(xmlXPathNodeSetCreate(NULL));
2406 xmlXPathNodeSetSort(nodes1);
2407 xmlXPathNodeSetSort(nodes2);
2408 return(xmlXPathNodeLeadingSorted(nodes1,
2409 xmlXPathNodeSetItem(nodes2, 1)));
2410}
2411
2412/**
2413 * xmlXPathNodeTrailingSorted:
2414 * @nodes: a node-set, sorted by document order
2415 * @node: a node
2416 *
2417 * Implements the EXSLT - Sets trailing() function:
2418 * node-set set:trailing (node-set, node-set)
2419 *
2420 * Returns the nodes in @nodes that follow @node in document order,
2421 * @nodes if @node is NULL or an empty node-set if @nodes
2422 * doesn't contain @node
2423 */
2424xmlNodeSetPtr
2425xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2426 int i, l;
2427 xmlNodePtr cur;
2428 xmlNodeSetPtr ret;
2429
2430 if (node == NULL)
2431 return(nodes);
2432
2433 ret = xmlXPathNodeSetCreate(NULL);
2434 if (xmlXPathNodeSetIsEmpty(nodes) ||
2435 (!xmlXPathNodeSetContains(nodes, node)))
2436 return(ret);
2437
2438 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002439 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002440 cur = xmlXPathNodeSetItem(nodes, i);
2441 if (cur == node)
2442 break;
2443 xmlXPathNodeSetAddUnique(ret, cur);
2444 }
2445 return(ret);
2446}
2447
2448/**
2449 * xmlXPathNodeTrailing:
2450 * @nodes: a node-set
2451 * @node: a node
2452 *
2453 * Implements the EXSLT - Sets trailing() function:
2454 * node-set set:trailing (node-set, node-set)
2455 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2456 * is called.
2457 *
2458 * Returns the nodes in @nodes that follow @node in document order,
2459 * @nodes if @node is NULL or an empty node-set if @nodes
2460 * doesn't contain @node
2461 */
2462xmlNodeSetPtr
2463xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2464 xmlXPathNodeSetSort(nodes);
2465 return(xmlXPathNodeTrailingSorted(nodes, node));
2466}
2467
2468/**
2469 * xmlXPathTrailingSorted:
2470 * @nodes1: a node-set, sorted by document order
2471 * @nodes2: a node-set, sorted by document order
2472 *
2473 * Implements the EXSLT - Sets trailing() function:
2474 * node-set set:trailing (node-set, node-set)
2475 *
2476 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2477 * in document order, @nodes1 if @nodes2 is NULL or empty or
2478 * an empty node-set if @nodes1 doesn't contain @nodes2
2479 */
2480xmlNodeSetPtr
2481xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2482 if (xmlXPathNodeSetIsEmpty(nodes2))
2483 return(nodes1);
2484 return(xmlXPathNodeTrailingSorted(nodes1,
2485 xmlXPathNodeSetItem(nodes2, 0)));
2486}
2487
2488/**
2489 * xmlXPathTrailing:
2490 * @nodes1: a node-set
2491 * @nodes2: a node-set
2492 *
2493 * Implements the EXSLT - Sets trailing() function:
2494 * node-set set:trailing (node-set, node-set)
2495 * @nodes1 and @nodes2 are sorted by document order, then
2496 * #xmlXPathTrailingSorted is called.
2497 *
2498 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2499 * in document order, @nodes1 if @nodes2 is NULL or empty or
2500 * an empty node-set if @nodes1 doesn't contain @nodes2
2501 */
2502xmlNodeSetPtr
2503xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2504 if (xmlXPathNodeSetIsEmpty(nodes2))
2505 return(nodes1);
2506 if (xmlXPathNodeSetIsEmpty(nodes1))
2507 return(xmlXPathNodeSetCreate(NULL));
2508 xmlXPathNodeSetSort(nodes1);
2509 xmlXPathNodeSetSort(nodes2);
2510 return(xmlXPathNodeTrailingSorted(nodes1,
2511 xmlXPathNodeSetItem(nodes2, 0)));
2512}
2513
Owen Taylor3473f882001-02-23 17:55:21 +00002514/************************************************************************
2515 * *
2516 * Routines to handle extra functions *
2517 * *
2518 ************************************************************************/
2519
2520/**
2521 * xmlXPathRegisterFunc:
2522 * @ctxt: the XPath context
2523 * @name: the function name
2524 * @f: the function implementation or NULL
2525 *
2526 * Register a new function. If @f is NULL it unregisters the function
2527 *
2528 * Returns 0 in case of success, -1 in case of error
2529 */
2530int
2531xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2532 xmlXPathFunction f) {
2533 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2534}
2535
2536/**
2537 * xmlXPathRegisterFuncNS:
2538 * @ctxt: the XPath context
2539 * @name: the function name
2540 * @ns_uri: the function namespace URI
2541 * @f: the function implementation or NULL
2542 *
2543 * Register a new function. If @f is NULL it unregisters the function
2544 *
2545 * Returns 0 in case of success, -1 in case of error
2546 */
2547int
2548xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2549 const xmlChar *ns_uri, xmlXPathFunction f) {
2550 if (ctxt == NULL)
2551 return(-1);
2552 if (name == NULL)
2553 return(-1);
2554
2555 if (ctxt->funcHash == NULL)
2556 ctxt->funcHash = xmlHashCreate(0);
2557 if (ctxt->funcHash == NULL)
2558 return(-1);
2559 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2560}
2561
2562/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002563 * xmlXPathRegisterFuncLookup:
2564 * @ctxt: the XPath context
2565 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002566 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00002567 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002568 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00002569 */
2570void
2571xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2572 xmlXPathFuncLookupFunc f,
2573 void *funcCtxt) {
2574 if (ctxt == NULL)
2575 return;
2576 ctxt->funcLookupFunc = (void *) f;
2577 ctxt->funcLookupData = funcCtxt;
2578}
2579
2580/**
Owen Taylor3473f882001-02-23 17:55:21 +00002581 * xmlXPathFunctionLookup:
2582 * @ctxt: the XPath context
2583 * @name: the function name
2584 *
2585 * Search in the Function array of the context for the given
2586 * function.
2587 *
2588 * Returns the xmlXPathFunction or NULL if not found
2589 */
2590xmlXPathFunction
2591xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002592 if (ctxt == NULL)
2593 return (NULL);
2594
2595 if (ctxt->funcLookupFunc != NULL) {
2596 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002597 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002598
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002599 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002600 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002601 if (ret != NULL)
2602 return(ret);
2603 }
Owen Taylor3473f882001-02-23 17:55:21 +00002604 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2605}
2606
2607/**
2608 * xmlXPathFunctionLookupNS:
2609 * @ctxt: the XPath context
2610 * @name: the function name
2611 * @ns_uri: the function namespace URI
2612 *
2613 * Search in the Function array of the context for the given
2614 * function.
2615 *
2616 * Returns the xmlXPathFunction or NULL if not found
2617 */
2618xmlXPathFunction
2619xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2620 const xmlChar *ns_uri) {
2621 if (ctxt == NULL)
2622 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002623 if (name == NULL)
2624 return(NULL);
2625
Thomas Broyerba4ad322001-07-26 16:55:21 +00002626 if (ctxt->funcLookupFunc != NULL) {
2627 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002628 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002629
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002630 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002631 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002632 if (ret != NULL)
2633 return(ret);
2634 }
2635
2636 if (ctxt->funcHash == NULL)
2637 return(NULL);
2638
Owen Taylor3473f882001-02-23 17:55:21 +00002639 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2640}
2641
2642/**
2643 * xmlXPathRegisteredFuncsCleanup:
2644 * @ctxt: the XPath context
2645 *
2646 * Cleanup the XPath context data associated to registered functions
2647 */
2648void
2649xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2650 if (ctxt == NULL)
2651 return;
2652
2653 xmlHashFree(ctxt->funcHash, NULL);
2654 ctxt->funcHash = NULL;
2655}
2656
2657/************************************************************************
2658 * *
2659 * Routines to handle Variable *
2660 * *
2661 ************************************************************************/
2662
2663/**
2664 * xmlXPathRegisterVariable:
2665 * @ctxt: the XPath context
2666 * @name: the variable name
2667 * @value: the variable value or NULL
2668 *
2669 * Register a new variable value. If @value is NULL it unregisters
2670 * the variable
2671 *
2672 * Returns 0 in case of success, -1 in case of error
2673 */
2674int
2675xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2676 xmlXPathObjectPtr value) {
2677 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2678}
2679
2680/**
2681 * xmlXPathRegisterVariableNS:
2682 * @ctxt: the XPath context
2683 * @name: the variable name
2684 * @ns_uri: the variable namespace URI
2685 * @value: the variable value or NULL
2686 *
2687 * Register a new variable value. If @value is NULL it unregisters
2688 * the variable
2689 *
2690 * Returns 0 in case of success, -1 in case of error
2691 */
2692int
2693xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2694 const xmlChar *ns_uri,
2695 xmlXPathObjectPtr value) {
2696 if (ctxt == NULL)
2697 return(-1);
2698 if (name == NULL)
2699 return(-1);
2700
2701 if (ctxt->varHash == NULL)
2702 ctxt->varHash = xmlHashCreate(0);
2703 if (ctxt->varHash == NULL)
2704 return(-1);
2705 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2706 (void *) value,
2707 (xmlHashDeallocator)xmlXPathFreeObject));
2708}
2709
2710/**
2711 * xmlXPathRegisterVariableLookup:
2712 * @ctxt: the XPath context
2713 * @f: the lookup function
2714 * @data: the lookup data
2715 *
2716 * register an external mechanism to do variable lookup
2717 */
2718void
2719xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2720 xmlXPathVariableLookupFunc f, void *data) {
2721 if (ctxt == NULL)
2722 return;
2723 ctxt->varLookupFunc = (void *) f;
2724 ctxt->varLookupData = data;
2725}
2726
2727/**
2728 * xmlXPathVariableLookup:
2729 * @ctxt: the XPath context
2730 * @name: the variable name
2731 *
2732 * Search in the Variable array of the context for the given
2733 * variable value.
2734 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002735 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002736 */
2737xmlXPathObjectPtr
2738xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2739 if (ctxt == NULL)
2740 return(NULL);
2741
2742 if (ctxt->varLookupFunc != NULL) {
2743 xmlXPathObjectPtr ret;
2744
2745 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2746 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00002747 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002748 }
2749 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
2750}
2751
2752/**
2753 * xmlXPathVariableLookupNS:
2754 * @ctxt: the XPath context
2755 * @name: the variable name
2756 * @ns_uri: the variable namespace URI
2757 *
2758 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00002759 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00002760 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002761 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002762 */
2763xmlXPathObjectPtr
2764xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2765 const xmlChar *ns_uri) {
2766 if (ctxt == NULL)
2767 return(NULL);
2768
2769 if (ctxt->varLookupFunc != NULL) {
2770 xmlXPathObjectPtr ret;
2771
2772 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2773 (ctxt->varLookupData, name, ns_uri);
2774 if (ret != NULL) return(ret);
2775 }
2776
2777 if (ctxt->varHash == NULL)
2778 return(NULL);
2779 if (name == NULL)
2780 return(NULL);
2781
Daniel Veillard8c357d52001-07-03 23:43:33 +00002782 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
2783 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00002784}
2785
2786/**
2787 * xmlXPathRegisteredVariablesCleanup:
2788 * @ctxt: the XPath context
2789 *
2790 * Cleanup the XPath context data associated to registered variables
2791 */
2792void
2793xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
2794 if (ctxt == NULL)
2795 return;
2796
Daniel Veillard76d66f42001-05-16 21:05:17 +00002797 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00002798 ctxt->varHash = NULL;
2799}
2800
2801/**
2802 * xmlXPathRegisterNs:
2803 * @ctxt: the XPath context
2804 * @prefix: the namespace prefix
2805 * @ns_uri: the namespace name
2806 *
2807 * Register a new namespace. If @ns_uri is NULL it unregisters
2808 * the namespace
2809 *
2810 * Returns 0 in case of success, -1 in case of error
2811 */
2812int
2813xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
2814 const xmlChar *ns_uri) {
2815 if (ctxt == NULL)
2816 return(-1);
2817 if (prefix == NULL)
2818 return(-1);
2819
2820 if (ctxt->nsHash == NULL)
2821 ctxt->nsHash = xmlHashCreate(10);
2822 if (ctxt->nsHash == NULL)
2823 return(-1);
2824 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) ns_uri,
2825 (xmlHashDeallocator)xmlFree));
2826}
2827
2828/**
2829 * xmlXPathNsLookup:
2830 * @ctxt: the XPath context
2831 * @prefix: the namespace prefix value
2832 *
2833 * Search in the namespace declaration array of the context for the given
2834 * namespace name associated to the given prefix
2835 *
2836 * Returns the value or NULL if not found
2837 */
2838const xmlChar *
2839xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
2840 if (ctxt == NULL)
2841 return(NULL);
2842 if (prefix == NULL)
2843 return(NULL);
2844
2845#ifdef XML_XML_NAMESPACE
2846 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
2847 return(XML_XML_NAMESPACE);
2848#endif
2849
Daniel Veillardc8f620b2001-04-30 20:31:33 +00002850 if (ctxt->namespaces != NULL) {
2851 int i;
2852
2853 for (i = 0;i < ctxt->nsNr;i++) {
2854 if ((ctxt->namespaces[i] != NULL) &&
2855 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
2856 return(ctxt->namespaces[i]->href);
2857 }
2858 }
Owen Taylor3473f882001-02-23 17:55:21 +00002859
2860 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
2861}
2862
2863/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002864 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00002865 * @ctxt: the XPath context
2866 *
2867 * Cleanup the XPath context data associated to registered variables
2868 */
2869void
2870xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
2871 if (ctxt == NULL)
2872 return;
2873
2874 xmlHashFree(ctxt->nsHash, NULL);
2875 ctxt->nsHash = NULL;
2876}
2877
2878/************************************************************************
2879 * *
2880 * Routines to handle Values *
2881 * *
2882 ************************************************************************/
2883
2884/* Allocations are terrible, one need to optimize all this !!! */
2885
2886/**
2887 * xmlXPathNewFloat:
2888 * @val: the double value
2889 *
2890 * Create a new xmlXPathObjectPtr of type double and of value @val
2891 *
2892 * Returns the newly created object.
2893 */
2894xmlXPathObjectPtr
2895xmlXPathNewFloat(double val) {
2896 xmlXPathObjectPtr ret;
2897
2898 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2899 if (ret == NULL) {
2900 xmlGenericError(xmlGenericErrorContext,
2901 "xmlXPathNewFloat: out of memory\n");
2902 return(NULL);
2903 }
2904 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2905 ret->type = XPATH_NUMBER;
2906 ret->floatval = val;
2907 return(ret);
2908}
2909
2910/**
2911 * xmlXPathNewBoolean:
2912 * @val: the boolean value
2913 *
2914 * Create a new xmlXPathObjectPtr of type boolean and of value @val
2915 *
2916 * Returns the newly created object.
2917 */
2918xmlXPathObjectPtr
2919xmlXPathNewBoolean(int val) {
2920 xmlXPathObjectPtr ret;
2921
2922 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2923 if (ret == NULL) {
2924 xmlGenericError(xmlGenericErrorContext,
2925 "xmlXPathNewBoolean: out of memory\n");
2926 return(NULL);
2927 }
2928 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2929 ret->type = XPATH_BOOLEAN;
2930 ret->boolval = (val != 0);
2931 return(ret);
2932}
2933
2934/**
2935 * xmlXPathNewString:
2936 * @val: the xmlChar * value
2937 *
2938 * Create a new xmlXPathObjectPtr of type string and of value @val
2939 *
2940 * Returns the newly created object.
2941 */
2942xmlXPathObjectPtr
2943xmlXPathNewString(const xmlChar *val) {
2944 xmlXPathObjectPtr ret;
2945
2946 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2947 if (ret == NULL) {
2948 xmlGenericError(xmlGenericErrorContext,
2949 "xmlXPathNewString: out of memory\n");
2950 return(NULL);
2951 }
2952 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2953 ret->type = XPATH_STRING;
2954 if (val != NULL)
2955 ret->stringval = xmlStrdup(val);
2956 else
2957 ret->stringval = xmlStrdup((const xmlChar *)"");
2958 return(ret);
2959}
2960
2961/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002962 * xmlXPathWrapString:
2963 * @val: the xmlChar * value
2964 *
2965 * Wraps the @val string into an XPath object.
2966 *
2967 * Returns the newly created object.
2968 */
2969xmlXPathObjectPtr
2970xmlXPathWrapString (xmlChar *val) {
2971 xmlXPathObjectPtr ret;
2972
2973 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2974 if (ret == NULL) {
2975 xmlGenericError(xmlGenericErrorContext,
2976 "xmlXPathWrapString: out of memory\n");
2977 return(NULL);
2978 }
2979 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2980 ret->type = XPATH_STRING;
2981 ret->stringval = val;
2982 return(ret);
2983}
2984
2985/**
Owen Taylor3473f882001-02-23 17:55:21 +00002986 * xmlXPathNewCString:
2987 * @val: the char * value
2988 *
2989 * Create a new xmlXPathObjectPtr of type string and of value @val
2990 *
2991 * Returns the newly created object.
2992 */
2993xmlXPathObjectPtr
2994xmlXPathNewCString(const char *val) {
2995 xmlXPathObjectPtr ret;
2996
2997 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2998 if (ret == NULL) {
2999 xmlGenericError(xmlGenericErrorContext,
3000 "xmlXPathNewCString: out of memory\n");
3001 return(NULL);
3002 }
3003 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3004 ret->type = XPATH_STRING;
3005 ret->stringval = xmlStrdup(BAD_CAST val);
3006 return(ret);
3007}
3008
3009/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003010 * xmlXPathWrapCString:
3011 * @val: the char * value
3012 *
3013 * Wraps a string into an XPath object.
3014 *
3015 * Returns the newly created object.
3016 */
3017xmlXPathObjectPtr
3018xmlXPathWrapCString (char * val) {
3019 return(xmlXPathWrapString((xmlChar *)(val)));
3020}
3021
3022/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003023 * xmlXPathWrapExternal:
3024 * @val: the user data
3025 *
3026 * Wraps the @val data into an XPath object.
3027 *
3028 * Returns the newly created object.
3029 */
3030xmlXPathObjectPtr
3031xmlXPathWrapExternal (void *val) {
3032 xmlXPathObjectPtr ret;
3033
3034 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3035 if (ret == NULL) {
3036 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003037 "xmlXPathWrapExternal: out of memory\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003038 return(NULL);
3039 }
3040 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3041 ret->type = XPATH_USERS;
3042 ret->user = val;
3043 return(ret);
3044}
3045
3046/**
Owen Taylor3473f882001-02-23 17:55:21 +00003047 * xmlXPathObjectCopy:
3048 * @val: the original object
3049 *
3050 * allocate a new copy of a given object
3051 *
3052 * Returns the newly created object.
3053 */
3054xmlXPathObjectPtr
3055xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3056 xmlXPathObjectPtr ret;
3057
3058 if (val == NULL)
3059 return(NULL);
3060
3061 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3062 if (ret == NULL) {
3063 xmlGenericError(xmlGenericErrorContext,
3064 "xmlXPathObjectCopy: out of memory\n");
3065 return(NULL);
3066 }
3067 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3068 switch (val->type) {
3069 case XPATH_BOOLEAN:
3070 case XPATH_NUMBER:
3071 case XPATH_POINT:
3072 case XPATH_RANGE:
3073 break;
3074 case XPATH_STRING:
3075 ret->stringval = xmlStrdup(val->stringval);
3076 break;
3077 case XPATH_XSLT_TREE:
3078 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003079 (val->nodesetval->nodeTab != NULL)) {
3080 ret->boolval = 1;
Daniel Veillard6ab38382001-10-06 13:08:27 +00003081 ret->user = xmlDocCopyNode(val->nodesetval->nodeTab[0],
3082 val->nodesetval->nodeTab[0]->doc, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003083 ret->nodesetval = xmlXPathNodeSetCreate(
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003084 (xmlNodePtr) ret->user);
3085 } else
Owen Taylor3473f882001-02-23 17:55:21 +00003086 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003087 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00003088 break;
3089 case XPATH_NODESET:
3090 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003091 /* Do not deallocate the copied tree value */
3092 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003093 break;
3094 case XPATH_LOCATIONSET:
3095#ifdef LIBXML_XPTR_ENABLED
3096 {
3097 xmlLocationSetPtr loc = val->user;
3098 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3099 break;
3100 }
3101#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00003102 case XPATH_USERS:
3103 ret->user = val->user;
3104 break;
3105 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00003106 xmlGenericError(xmlGenericErrorContext,
3107 "xmlXPathObjectCopy: unsupported type %d\n",
3108 val->type);
3109 break;
3110 }
3111 return(ret);
3112}
3113
3114/**
3115 * xmlXPathFreeObject:
3116 * @obj: the object to free
3117 *
3118 * Free up an xmlXPathObjectPtr object.
3119 */
3120void
3121xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3122 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003123 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00003124 if (obj->boolval) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003125 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003126 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00003127 xmlFreeNodeList((xmlNodePtr) obj->user);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003128 } else if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00003129 xmlXPathFreeValueTree(obj->nodesetval);
3130 } else {
3131 if (obj->nodesetval != NULL)
3132 xmlXPathFreeNodeSet(obj->nodesetval);
3133 }
Owen Taylor3473f882001-02-23 17:55:21 +00003134#ifdef LIBXML_XPTR_ENABLED
3135 } else if (obj->type == XPATH_LOCATIONSET) {
3136 if (obj->user != NULL)
3137 xmlXPtrFreeLocationSet(obj->user);
3138#endif
3139 } else if (obj->type == XPATH_STRING) {
3140 if (obj->stringval != NULL)
3141 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00003142 }
3143
Owen Taylor3473f882001-02-23 17:55:21 +00003144 xmlFree(obj);
3145}
3146
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003147
3148/************************************************************************
3149 * *
3150 * Type Casting Routines *
3151 * *
3152 ************************************************************************/
3153
3154/**
3155 * xmlXPathCastBooleanToString:
3156 * @val: a boolean
3157 *
3158 * Converts a boolean to its string value.
3159 *
3160 * Returns a newly allocated string.
3161 */
3162xmlChar *
3163xmlXPathCastBooleanToString (int val) {
3164 xmlChar *ret;
3165 if (val)
3166 ret = xmlStrdup((const xmlChar *) "true");
3167 else
3168 ret = xmlStrdup((const xmlChar *) "false");
3169 return(ret);
3170}
3171
3172/**
3173 * xmlXPathCastNumberToString:
3174 * @val: a number
3175 *
3176 * Converts a number to its string value.
3177 *
3178 * Returns a newly allocated string.
3179 */
3180xmlChar *
3181xmlXPathCastNumberToString (double val) {
3182 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00003183 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003184 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003185 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003186 break;
3187 case -1:
3188 ret = xmlStrdup((const xmlChar *) "-Infinity");
3189 break;
3190 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003191 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003192 ret = xmlStrdup((const xmlChar *) "NaN");
3193 } else {
3194 /* could be improved */
3195 char buf[100];
3196 xmlXPathFormatNumber(val, buf, 100);
3197 ret = xmlStrdup((const xmlChar *) buf);
3198 }
3199 }
3200 return(ret);
3201}
3202
3203/**
3204 * xmlXPathCastNodeToString:
3205 * @node: a node
3206 *
3207 * Converts a node to its string value.
3208 *
3209 * Returns a newly allocated string.
3210 */
3211xmlChar *
3212xmlXPathCastNodeToString (xmlNodePtr node) {
3213 return(xmlNodeGetContent(node));
3214}
3215
3216/**
3217 * xmlXPathCastNodeSetToString:
3218 * @ns: a node-set
3219 *
3220 * Converts a node-set to its string value.
3221 *
3222 * Returns a newly allocated string.
3223 */
3224xmlChar *
3225xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3226 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3227 return(xmlStrdup((const xmlChar *) ""));
3228
3229 xmlXPathNodeSetSort(ns);
3230 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3231}
3232
3233/**
3234 * xmlXPathCastToString:
3235 * @val: an XPath object
3236 *
3237 * Converts an existing object to its string() equivalent
3238 *
3239 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003240 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003241 * string object).
3242 */
3243xmlChar *
3244xmlXPathCastToString(xmlXPathObjectPtr val) {
3245 xmlChar *ret = NULL;
3246
3247 if (val == NULL)
3248 return(xmlStrdup((const xmlChar *) ""));
3249 switch (val->type) {
3250 case XPATH_UNDEFINED:
3251#ifdef DEBUG_EXPR
3252 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3253#endif
3254 ret = xmlStrdup((const xmlChar *) "");
3255 break;
3256 case XPATH_XSLT_TREE:
3257 case XPATH_NODESET:
3258 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3259 break;
3260 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00003261 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003262 case XPATH_BOOLEAN:
3263 ret = xmlXPathCastBooleanToString(val->boolval);
3264 break;
3265 case XPATH_NUMBER: {
3266 ret = xmlXPathCastNumberToString(val->floatval);
3267 break;
3268 }
3269 case XPATH_USERS:
3270 case XPATH_POINT:
3271 case XPATH_RANGE:
3272 case XPATH_LOCATIONSET:
3273 TODO
3274 ret = xmlStrdup((const xmlChar *) "");
3275 break;
3276 }
3277 return(ret);
3278}
3279
3280/**
3281 * xmlXPathConvertString:
3282 * @val: an XPath object
3283 *
3284 * Converts an existing object to its string() equivalent
3285 *
3286 * Returns the new object, the old one is freed (or the operation
3287 * is done directly on @val)
3288 */
3289xmlXPathObjectPtr
3290xmlXPathConvertString(xmlXPathObjectPtr val) {
3291 xmlChar *res = NULL;
3292
3293 if (val == NULL)
3294 return(xmlXPathNewCString(""));
3295
3296 switch (val->type) {
3297 case XPATH_UNDEFINED:
3298#ifdef DEBUG_EXPR
3299 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3300#endif
3301 break;
3302 case XPATH_XSLT_TREE:
3303 case XPATH_NODESET:
3304 res = xmlXPathCastNodeSetToString(val->nodesetval);
3305 break;
3306 case XPATH_STRING:
3307 return(val);
3308 case XPATH_BOOLEAN:
3309 res = xmlXPathCastBooleanToString(val->boolval);
3310 break;
3311 case XPATH_NUMBER:
3312 res = xmlXPathCastNumberToString(val->floatval);
3313 break;
3314 case XPATH_USERS:
3315 case XPATH_POINT:
3316 case XPATH_RANGE:
3317 case XPATH_LOCATIONSET:
3318 TODO;
3319 break;
3320 }
3321 xmlXPathFreeObject(val);
3322 if (res == NULL)
3323 return(xmlXPathNewCString(""));
3324 return(xmlXPathWrapString(res));
3325}
3326
3327/**
3328 * xmlXPathCastBooleanToNumber:
3329 * @val: a boolean
3330 *
3331 * Converts a boolean to its number value
3332 *
3333 * Returns the number value
3334 */
3335double
3336xmlXPathCastBooleanToNumber(int val) {
3337 if (val)
3338 return(1.0);
3339 return(0.0);
3340}
3341
3342/**
3343 * xmlXPathCastStringToNumber:
3344 * @val: a string
3345 *
3346 * Converts a string to its number value
3347 *
3348 * Returns the number value
3349 */
3350double
3351xmlXPathCastStringToNumber(const xmlChar * val) {
3352 return(xmlXPathStringEvalNumber(val));
3353}
3354
3355/**
3356 * xmlXPathCastNodeToNumber:
3357 * @node: a node
3358 *
3359 * Converts a node to its number value
3360 *
3361 * Returns the number value
3362 */
3363double
3364xmlXPathCastNodeToNumber (xmlNodePtr node) {
3365 xmlChar *strval;
3366 double ret;
3367
3368 if (node == NULL)
3369 return(xmlXPathNAN);
3370 strval = xmlXPathCastNodeToString(node);
3371 if (strval == NULL)
3372 return(xmlXPathNAN);
3373 ret = xmlXPathCastStringToNumber(strval);
3374 xmlFree(strval);
3375
3376 return(ret);
3377}
3378
3379/**
3380 * xmlXPathCastNodeSetToNumber:
3381 * @ns: a node-set
3382 *
3383 * Converts a node-set to its number value
3384 *
3385 * Returns the number value
3386 */
3387double
3388xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3389 xmlChar *str;
3390 double ret;
3391
3392 if (ns == NULL)
3393 return(xmlXPathNAN);
3394 str = xmlXPathCastNodeSetToString(ns);
3395 ret = xmlXPathCastStringToNumber(str);
3396 xmlFree(str);
3397 return(ret);
3398}
3399
3400/**
3401 * xmlXPathCastToNumber:
3402 * @val: an XPath object
3403 *
3404 * Converts an XPath object to its number value
3405 *
3406 * Returns the number value
3407 */
3408double
3409xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3410 double ret = 0.0;
3411
3412 if (val == NULL)
3413 return(xmlXPathNAN);
3414 switch (val->type) {
3415 case XPATH_UNDEFINED:
3416#ifdef DEGUB_EXPR
3417 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3418#endif
3419 ret = xmlXPathNAN;
3420 break;
3421 case XPATH_XSLT_TREE:
3422 case XPATH_NODESET:
3423 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3424 break;
3425 case XPATH_STRING:
3426 ret = xmlXPathCastStringToNumber(val->stringval);
3427 break;
3428 case XPATH_NUMBER:
3429 ret = val->floatval;
3430 break;
3431 case XPATH_BOOLEAN:
3432 ret = xmlXPathCastBooleanToNumber(val->boolval);
3433 break;
3434 case XPATH_USERS:
3435 case XPATH_POINT:
3436 case XPATH_RANGE:
3437 case XPATH_LOCATIONSET:
3438 TODO;
3439 ret = xmlXPathNAN;
3440 break;
3441 }
3442 return(ret);
3443}
3444
3445/**
3446 * xmlXPathConvertNumber:
3447 * @val: an XPath object
3448 *
3449 * Converts an existing object to its number() equivalent
3450 *
3451 * Returns the new object, the old one is freed (or the operation
3452 * is done directly on @val)
3453 */
3454xmlXPathObjectPtr
3455xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3456 xmlXPathObjectPtr ret;
3457
3458 if (val == NULL)
3459 return(xmlXPathNewFloat(0.0));
3460 if (val->type == XPATH_NUMBER)
3461 return(val);
3462 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3463 xmlXPathFreeObject(val);
3464 return(ret);
3465}
3466
3467/**
3468 * xmlXPathCastNumberToBoolean:
3469 * @val: a number
3470 *
3471 * Converts a number to its boolean value
3472 *
3473 * Returns the boolean value
3474 */
3475int
3476xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003477 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003478 return(0);
3479 return(1);
3480}
3481
3482/**
3483 * xmlXPathCastStringToBoolean:
3484 * @val: a string
3485 *
3486 * Converts a string to its boolean value
3487 *
3488 * Returns the boolean value
3489 */
3490int
3491xmlXPathCastStringToBoolean (const xmlChar *val) {
3492 if ((val == NULL) || (xmlStrlen(val) == 0))
3493 return(0);
3494 return(1);
3495}
3496
3497/**
3498 * xmlXPathCastNodeSetToBoolean:
3499 * @ns: a node-set
3500 *
3501 * Converts a node-set to its boolean value
3502 *
3503 * Returns the boolean value
3504 */
3505int
3506xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3507 if ((ns == NULL) || (ns->nodeNr == 0))
3508 return(0);
3509 return(1);
3510}
3511
3512/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003513 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003514 * @val: an XPath object
3515 *
3516 * Converts an XPath object to its boolean value
3517 *
3518 * Returns the boolean value
3519 */
3520int
3521xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3522 int ret = 0;
3523
3524 if (val == NULL)
3525 return(0);
3526 switch (val->type) {
3527 case XPATH_UNDEFINED:
3528#ifdef DEBUG_EXPR
3529 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3530#endif
3531 ret = 0;
3532 break;
3533 case XPATH_XSLT_TREE:
3534 case XPATH_NODESET:
3535 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3536 break;
3537 case XPATH_STRING:
3538 ret = xmlXPathCastStringToBoolean(val->stringval);
3539 break;
3540 case XPATH_NUMBER:
3541 ret = xmlXPathCastNumberToBoolean(val->floatval);
3542 break;
3543 case XPATH_BOOLEAN:
3544 ret = val->boolval;
3545 break;
3546 case XPATH_USERS:
3547 case XPATH_POINT:
3548 case XPATH_RANGE:
3549 case XPATH_LOCATIONSET:
3550 TODO;
3551 ret = 0;
3552 break;
3553 }
3554 return(ret);
3555}
3556
3557
3558/**
3559 * xmlXPathConvertBoolean:
3560 * @val: an XPath object
3561 *
3562 * Converts an existing object to its boolean() equivalent
3563 *
3564 * Returns the new object, the old one is freed (or the operation
3565 * is done directly on @val)
3566 */
3567xmlXPathObjectPtr
3568xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3569 xmlXPathObjectPtr ret;
3570
3571 if (val == NULL)
3572 return(xmlXPathNewBoolean(0));
3573 if (val->type == XPATH_BOOLEAN)
3574 return(val);
3575 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3576 xmlXPathFreeObject(val);
3577 return(ret);
3578}
3579
Owen Taylor3473f882001-02-23 17:55:21 +00003580/************************************************************************
3581 * *
3582 * Routines to handle XPath contexts *
3583 * *
3584 ************************************************************************/
3585
3586/**
3587 * xmlXPathNewContext:
3588 * @doc: the XML document
3589 *
3590 * Create a new xmlXPathContext
3591 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00003592 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00003593 */
3594xmlXPathContextPtr
3595xmlXPathNewContext(xmlDocPtr doc) {
3596 xmlXPathContextPtr ret;
3597
3598 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3599 if (ret == NULL) {
3600 xmlGenericError(xmlGenericErrorContext,
3601 "xmlXPathNewContext: out of memory\n");
3602 return(NULL);
3603 }
3604 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3605 ret->doc = doc;
3606 ret->node = NULL;
3607
3608 ret->varHash = NULL;
3609
3610 ret->nb_types = 0;
3611 ret->max_types = 0;
3612 ret->types = NULL;
3613
3614 ret->funcHash = xmlHashCreate(0);
3615
3616 ret->nb_axis = 0;
3617 ret->max_axis = 0;
3618 ret->axis = NULL;
3619
3620 ret->nsHash = NULL;
3621 ret->user = NULL;
3622
3623 ret->contextSize = -1;
3624 ret->proximityPosition = -1;
3625
3626 xmlXPathRegisterAllFunctions(ret);
3627
3628 return(ret);
3629}
3630
3631/**
3632 * xmlXPathFreeContext:
3633 * @ctxt: the context to free
3634 *
3635 * Free up an xmlXPathContext
3636 */
3637void
3638xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3639 xmlXPathRegisteredNsCleanup(ctxt);
3640 xmlXPathRegisteredFuncsCleanup(ctxt);
3641 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003642 xmlFree(ctxt);
3643}
3644
3645/************************************************************************
3646 * *
3647 * Routines to handle XPath parser contexts *
3648 * *
3649 ************************************************************************/
3650
3651#define CHECK_CTXT(ctxt) \
3652 if (ctxt == NULL) { \
3653 xmlGenericError(xmlGenericErrorContext, \
3654 "%s:%d Internal error: ctxt == NULL\n", \
3655 __FILE__, __LINE__); \
3656 } \
3657
3658
3659#define CHECK_CONTEXT(ctxt) \
3660 if (ctxt == NULL) { \
3661 xmlGenericError(xmlGenericErrorContext, \
3662 "%s:%d Internal error: no context\n", \
3663 __FILE__, __LINE__); \
3664 } \
3665 else if (ctxt->doc == NULL) { \
3666 xmlGenericError(xmlGenericErrorContext, \
3667 "%s:%d Internal error: no document\n", \
3668 __FILE__, __LINE__); \
3669 } \
3670 else if (ctxt->doc->children == NULL) { \
3671 xmlGenericError(xmlGenericErrorContext, \
3672 "%s:%d Internal error: document without root\n", \
3673 __FILE__, __LINE__); \
3674 } \
3675
3676
3677/**
3678 * xmlXPathNewParserContext:
3679 * @str: the XPath expression
3680 * @ctxt: the XPath context
3681 *
3682 * Create a new xmlXPathParserContext
3683 *
3684 * Returns the xmlXPathParserContext just allocated.
3685 */
3686xmlXPathParserContextPtr
3687xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3688 xmlXPathParserContextPtr ret;
3689
3690 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3691 if (ret == NULL) {
3692 xmlGenericError(xmlGenericErrorContext,
3693 "xmlXPathNewParserContext: out of memory\n");
3694 return(NULL);
3695 }
3696 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3697 ret->cur = ret->base = str;
3698 ret->context = ctxt;
3699
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003700 ret->comp = xmlXPathNewCompExpr();
3701 if (ret->comp == NULL) {
3702 xmlFree(ret->valueTab);
3703 xmlFree(ret);
3704 return(NULL);
3705 }
3706
3707 return(ret);
3708}
3709
3710/**
3711 * xmlXPathCompParserContext:
3712 * @comp: the XPath compiled expression
3713 * @ctxt: the XPath context
3714 *
3715 * Create a new xmlXPathParserContext when processing a compiled expression
3716 *
3717 * Returns the xmlXPathParserContext just allocated.
3718 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003719static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003720xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3721 xmlXPathParserContextPtr ret;
3722
3723 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3724 if (ret == NULL) {
3725 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003726 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003727 return(NULL);
3728 }
3729 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3730
Owen Taylor3473f882001-02-23 17:55:21 +00003731 /* Allocate the value stack */
3732 ret->valueTab = (xmlXPathObjectPtr *)
3733 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003734 if (ret->valueTab == NULL) {
3735 xmlFree(ret);
3736 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003737 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003738 return(NULL);
3739 }
Owen Taylor3473f882001-02-23 17:55:21 +00003740 ret->valueNr = 0;
3741 ret->valueMax = 10;
3742 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003743
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00003744 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003745 ret->comp = comp;
3746
Owen Taylor3473f882001-02-23 17:55:21 +00003747 return(ret);
3748}
3749
3750/**
3751 * xmlXPathFreeParserContext:
3752 * @ctxt: the context to free
3753 *
3754 * Free up an xmlXPathParserContext
3755 */
3756void
3757xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
3758 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003759 xmlFree(ctxt->valueTab);
3760 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003761 if (ctxt->comp)
3762 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00003763 xmlFree(ctxt);
3764}
3765
3766/************************************************************************
3767 * *
3768 * The implicit core function library *
3769 * *
3770 ************************************************************************/
3771
Owen Taylor3473f882001-02-23 17:55:21 +00003772/**
Daniel Veillardf06307e2001-07-03 10:35:50 +00003773 * xmlXPathNodeStringHash:
3774 * @node: a node pointer
3775 *
3776 * Function computing the beginning of the string value of the node,
3777 * used to speed up comparisons
3778 *
3779 * Returns an int usable as a hash
3780 */
3781static unsigned int
3782xmlXPathNodeValHash(xmlNodePtr node) {
3783 int len = 2;
3784 const xmlChar * string = NULL;
3785 xmlNodePtr tmp = NULL;
3786 unsigned int ret = 0;
3787
3788 if (node == NULL)
3789 return(0);
3790
3791
3792 switch (node->type) {
3793 case XML_COMMENT_NODE:
3794 case XML_PI_NODE:
3795 case XML_CDATA_SECTION_NODE:
3796 case XML_TEXT_NODE:
3797 string = node->content;
3798 if (string == NULL)
3799 return(0);
3800 if (string[0] == 0)
3801 return(0);
3802 return(((unsigned int) string[0]) +
3803 (((unsigned int) string[1]) << 8));
3804 case XML_NAMESPACE_DECL:
3805 string = ((xmlNsPtr)node)->href;
3806 if (string == NULL)
3807 return(0);
3808 if (string[0] == 0)
3809 return(0);
3810 return(((unsigned int) string[0]) +
3811 (((unsigned int) string[1]) << 8));
3812 case XML_ATTRIBUTE_NODE:
3813 tmp = ((xmlAttrPtr) node)->children;
3814 break;
3815 case XML_ELEMENT_NODE:
3816 tmp = node->children;
3817 break;
3818 default:
3819 return(0);
3820 }
3821 while (tmp != NULL) {
3822 switch (tmp->type) {
3823 case XML_COMMENT_NODE:
3824 case XML_PI_NODE:
3825 case XML_CDATA_SECTION_NODE:
3826 case XML_TEXT_NODE:
3827 string = tmp->content;
3828 break;
3829 case XML_NAMESPACE_DECL:
3830 string = ((xmlNsPtr)tmp)->href;
3831 break;
3832 default:
3833 break;
3834 }
3835 if ((string != NULL) && (string[0] != 0)) {
3836 if (string[0] == 0)
3837 return(0);
3838 if (len == 1) {
3839 return(ret + (((unsigned int) string[0]) << 8));
3840 }
3841 if (string[1] == 0) {
3842 len = 1;
3843 ret = (unsigned int) string[0];
3844 } else {
3845 return(((unsigned int) string[0]) +
3846 (((unsigned int) string[1]) << 8));
3847 }
3848 }
3849 /*
3850 * Skip to next node
3851 */
3852 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
3853 if (tmp->children->type != XML_ENTITY_DECL) {
3854 tmp = tmp->children;
3855 continue;
3856 }
3857 }
3858 if (tmp == node)
3859 break;
3860
3861 if (tmp->next != NULL) {
3862 tmp = tmp->next;
3863 continue;
3864 }
3865
3866 do {
3867 tmp = tmp->parent;
3868 if (tmp == NULL)
3869 break;
3870 if (tmp == node) {
3871 tmp = NULL;
3872 break;
3873 }
3874 if (tmp->next != NULL) {
3875 tmp = tmp->next;
3876 break;
3877 }
3878 } while (tmp != NULL);
3879 }
3880 return(ret);
3881}
3882
3883/**
3884 * xmlXPathStringHash:
3885 * @string: a string
3886 *
3887 * Function computing the beginning of the string value of the node,
3888 * used to speed up comparisons
3889 *
3890 * Returns an int usable as a hash
3891 */
3892static unsigned int
3893xmlXPathStringHash(const xmlChar * string) {
3894 if (string == NULL)
3895 return((unsigned int) 0);
3896 if (string[0] == 0)
3897 return(0);
3898 return(((unsigned int) string[0]) +
3899 (((unsigned int) string[1]) << 8));
3900}
3901
3902/**
Owen Taylor3473f882001-02-23 17:55:21 +00003903 * xmlXPathCompareNodeSetFloat:
3904 * @ctxt: the XPath Parser context
3905 * @inf: less than (1) or greater than (0)
3906 * @strict: is the comparison strict
3907 * @arg: the node set
3908 * @f: the value
3909 *
3910 * Implement the compare operation between a nodeset and a number
3911 * @ns < @val (1, 1, ...
3912 * @ns <= @val (1, 0, ...
3913 * @ns > @val (0, 1, ...
3914 * @ns >= @val (0, 0, ...
3915 *
3916 * If one object to be compared is a node-set and the other is a number,
3917 * then the comparison will be true if and only if there is a node in the
3918 * node-set such that the result of performing the comparison on the number
3919 * to be compared and on the result of converting the string-value of that
3920 * node to a number using the number function is true.
3921 *
3922 * Returns 0 or 1 depending on the results of the test.
3923 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003924static int
Owen Taylor3473f882001-02-23 17:55:21 +00003925xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
3926 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
3927 int i, ret = 0;
3928 xmlNodeSetPtr ns;
3929 xmlChar *str2;
3930
3931 if ((f == NULL) || (arg == NULL) ||
3932 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3933 xmlXPathFreeObject(arg);
3934 xmlXPathFreeObject(f);
3935 return(0);
3936 }
3937 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003938 if (ns != NULL) {
3939 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003940 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003941 if (str2 != NULL) {
3942 valuePush(ctxt,
3943 xmlXPathNewString(str2));
3944 xmlFree(str2);
3945 xmlXPathNumberFunction(ctxt, 1);
3946 valuePush(ctxt, xmlXPathObjectCopy(f));
3947 ret = xmlXPathCompareValues(ctxt, inf, strict);
3948 if (ret)
3949 break;
3950 }
3951 }
Owen Taylor3473f882001-02-23 17:55:21 +00003952 }
3953 xmlXPathFreeObject(arg);
3954 xmlXPathFreeObject(f);
3955 return(ret);
3956}
3957
3958/**
3959 * xmlXPathCompareNodeSetString:
3960 * @ctxt: the XPath Parser context
3961 * @inf: less than (1) or greater than (0)
3962 * @strict: is the comparison strict
3963 * @arg: the node set
3964 * @s: the value
3965 *
3966 * Implement the compare operation between a nodeset and a string
3967 * @ns < @val (1, 1, ...
3968 * @ns <= @val (1, 0, ...
3969 * @ns > @val (0, 1, ...
3970 * @ns >= @val (0, 0, ...
3971 *
3972 * If one object to be compared is a node-set and the other is a string,
3973 * then the comparison will be true if and only if there is a node in
3974 * the node-set such that the result of performing the comparison on the
3975 * string-value of the node and the other string is true.
3976 *
3977 * Returns 0 or 1 depending on the results of the test.
3978 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003979static int
Owen Taylor3473f882001-02-23 17:55:21 +00003980xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
3981 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
3982 int i, ret = 0;
3983 xmlNodeSetPtr ns;
3984 xmlChar *str2;
3985
3986 if ((s == NULL) || (arg == NULL) ||
3987 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3988 xmlXPathFreeObject(arg);
3989 xmlXPathFreeObject(s);
3990 return(0);
3991 }
3992 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003993 if (ns != NULL) {
3994 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003995 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003996 if (str2 != NULL) {
3997 valuePush(ctxt,
3998 xmlXPathNewString(str2));
3999 xmlFree(str2);
4000 valuePush(ctxt, xmlXPathObjectCopy(s));
4001 ret = xmlXPathCompareValues(ctxt, inf, strict);
4002 if (ret)
4003 break;
4004 }
4005 }
Owen Taylor3473f882001-02-23 17:55:21 +00004006 }
4007 xmlXPathFreeObject(arg);
4008 xmlXPathFreeObject(s);
4009 return(ret);
4010}
4011
4012/**
4013 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004014 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00004015 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004016 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00004017 * @arg2: the second node set object
4018 *
4019 * Implement the compare operation on nodesets:
4020 *
4021 * If both objects to be compared are node-sets, then the comparison
4022 * will be true if and only if there is a node in the first node-set
4023 * and a node in the second node-set such that the result of performing
4024 * the comparison on the string-values of the two nodes is true.
4025 * ....
4026 * When neither object to be compared is a node-set and the operator
4027 * is <=, <, >= or >, then the objects are compared by converting both
4028 * objects to numbers and comparing the numbers according to IEEE 754.
4029 * ....
4030 * The number function converts its argument to a number as follows:
4031 * - a string that consists of optional whitespace followed by an
4032 * optional minus sign followed by a Number followed by whitespace
4033 * is converted to the IEEE 754 number that is nearest (according
4034 * to the IEEE 754 round-to-nearest rule) to the mathematical value
4035 * represented by the string; any other string is converted to NaN
4036 *
4037 * Conclusion all nodes need to be converted first to their string value
4038 * and then the comparison must be done when possible
4039 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004040static int
4041xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00004042 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4043 int i, j, init = 0;
4044 double val1;
4045 double *values2;
4046 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004047 xmlNodeSetPtr ns1;
4048 xmlNodeSetPtr ns2;
4049
4050 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004051 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4052 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004053 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004054 }
Owen Taylor3473f882001-02-23 17:55:21 +00004055 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004056 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4057 xmlXPathFreeObject(arg1);
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
4062 ns1 = arg1->nodesetval;
4063 ns2 = arg2->nodesetval;
4064
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004065 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004066 xmlXPathFreeObject(arg1);
4067 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004068 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004069 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004070 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004071 xmlXPathFreeObject(arg1);
4072 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004073 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004074 }
Owen Taylor3473f882001-02-23 17:55:21 +00004075
4076 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4077 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004078 xmlXPathFreeObject(arg1);
4079 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004080 return(0);
4081 }
4082 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004083 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004084 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004085 continue;
4086 for (j = 0;j < ns2->nodeNr;j++) {
4087 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004088 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004089 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004090 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004091 continue;
4092 if (inf && strict)
4093 ret = (val1 < values2[j]);
4094 else if (inf && !strict)
4095 ret = (val1 <= values2[j]);
4096 else if (!inf && strict)
4097 ret = (val1 > values2[j]);
4098 else if (!inf && !strict)
4099 ret = (val1 >= values2[j]);
4100 if (ret)
4101 break;
4102 }
4103 if (ret)
4104 break;
4105 init = 1;
4106 }
4107 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004108 xmlXPathFreeObject(arg1);
4109 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004110 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004111}
4112
4113/**
4114 * xmlXPathCompareNodeSetValue:
4115 * @ctxt: the XPath Parser context
4116 * @inf: less than (1) or greater than (0)
4117 * @strict: is the comparison strict
4118 * @arg: the node set
4119 * @val: the value
4120 *
4121 * Implement the compare operation between a nodeset and a value
4122 * @ns < @val (1, 1, ...
4123 * @ns <= @val (1, 0, ...
4124 * @ns > @val (0, 1, ...
4125 * @ns >= @val (0, 0, ...
4126 *
4127 * If one object to be compared is a node-set and the other is a boolean,
4128 * then the comparison will be true if and only if the result of performing
4129 * the comparison on the boolean and on the result of converting
4130 * the node-set to a boolean using the boolean function is true.
4131 *
4132 * Returns 0 or 1 depending on the results of the test.
4133 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004134static int
Owen Taylor3473f882001-02-23 17:55:21 +00004135xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4136 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4137 if ((val == NULL) || (arg == NULL) ||
4138 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4139 return(0);
4140
4141 switch(val->type) {
4142 case XPATH_NUMBER:
4143 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4144 case XPATH_NODESET:
4145 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004146 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004147 case XPATH_STRING:
4148 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4149 case XPATH_BOOLEAN:
4150 valuePush(ctxt, arg);
4151 xmlXPathBooleanFunction(ctxt, 1);
4152 valuePush(ctxt, val);
4153 return(xmlXPathCompareValues(ctxt, inf, strict));
4154 default:
4155 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004156 }
4157 return(0);
4158}
4159
4160/**
4161 * xmlXPathEqualNodeSetString
4162 * @arg: the nodeset object argument
4163 * @str: the string to compare to.
4164 *
4165 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4166 * If one object to be compared is a node-set and the other is a string,
4167 * then the comparison will be true if and only if there is a node in
4168 * the node-set such that the result of performing the comparison on the
4169 * string-value of the node and the other string is true.
4170 *
4171 * Returns 0 or 1 depending on the results of the test.
4172 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004173static int
Daniel Veillardf06307e2001-07-03 10:35:50 +00004174xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str)
4175{
Owen Taylor3473f882001-02-23 17:55:21 +00004176 int i;
4177 xmlNodeSetPtr ns;
4178 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004179 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004180
4181 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004182 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4183 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004184 ns = arg->nodesetval;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004185 hash = xmlXPathStringHash(str);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004186 if (ns == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004187 return (0);
Daniel Veillard73c9c042001-07-05 20:02:54 +00004188 if (ns->nodeNr <= 0) {
4189 if (hash == 0)
4190 return(1);
4191 return(0);
4192 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004193 for (i = 0; i < ns->nodeNr; i++) {
4194 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4195 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4196 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4197 xmlFree(str2);
4198 return (1);
4199 }
4200 if (str2 != NULL)
4201 xmlFree(str2);
4202 }
Owen Taylor3473f882001-02-23 17:55:21 +00004203 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004204 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004205}
4206
4207/**
4208 * xmlXPathEqualNodeSetFloat
4209 * @arg: the nodeset object argument
4210 * @f: the float to compare to
4211 *
4212 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4213 * If one object to be compared is a node-set and the other is a number,
4214 * then the comparison will be true if and only if there is a node in
4215 * the node-set such that the result of performing the comparison on the
4216 * number to be compared and on the result of converting the string-value
4217 * of that node to a number using the number function is true.
4218 *
4219 * Returns 0 or 1 depending on the results of the test.
4220 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004221static int
Owen Taylor3473f882001-02-23 17:55:21 +00004222xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, double f) {
4223 char buf[100] = "";
4224
4225 if ((arg == NULL) ||
4226 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4227 return(0);
4228
Bjorn Reesee1dc0112001-03-03 12:09:03 +00004229 xmlXPathFormatNumber(f, buf, sizeof(buf));
Owen Taylor3473f882001-02-23 17:55:21 +00004230 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
4231}
4232
4233
4234/**
4235 * xmlXPathEqualNodeSets
4236 * @arg1: first nodeset object argument
4237 * @arg2: second nodeset object argument
4238 *
4239 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
4240 * If both objects to be compared are node-sets, then the comparison
4241 * will be true if and only if there is a node in the first node-set and
4242 * a node in the second node-set such that the result of performing the
4243 * comparison on the string-values of the two nodes is true.
4244 *
4245 * (needless to say, this is a costly operation)
4246 *
4247 * Returns 0 or 1 depending on the results of the test.
4248 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004249static int
Owen Taylor3473f882001-02-23 17:55:21 +00004250xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4251 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004252 unsigned int *hashs1;
4253 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004254 xmlChar **values1;
4255 xmlChar **values2;
4256 int ret = 0;
4257 xmlNodeSetPtr ns1;
4258 xmlNodeSetPtr ns2;
4259
4260 if ((arg1 == NULL) ||
4261 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4262 return(0);
4263 if ((arg2 == NULL) ||
4264 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4265 return(0);
4266
4267 ns1 = arg1->nodesetval;
4268 ns2 = arg2->nodesetval;
4269
Daniel Veillard911f49a2001-04-07 15:39:35 +00004270 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004271 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004272 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004273 return(0);
4274
4275 /*
4276 * check if there is a node pertaining to both sets
4277 */
4278 for (i = 0;i < ns1->nodeNr;i++)
4279 for (j = 0;j < ns2->nodeNr;j++)
4280 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4281 return(1);
4282
4283 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
4284 if (values1 == NULL)
4285 return(0);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004286 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4287 if (hashs1 == NULL) {
4288 xmlFree(values1);
4289 return(0);
4290 }
Owen Taylor3473f882001-02-23 17:55:21 +00004291 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4292 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4293 if (values2 == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004294 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004295 xmlFree(values1);
4296 return(0);
4297 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004298 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4299 if (hashs2 == NULL) {
4300 xmlFree(hashs1);
4301 xmlFree(values1);
4302 xmlFree(values2);
4303 return(0);
4304 }
Owen Taylor3473f882001-02-23 17:55:21 +00004305 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4306 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004307 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004308 for (j = 0;j < ns2->nodeNr;j++) {
4309 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004310 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
4311 if (hashs1[i] == hashs2[j]) {
4312 if (values1[i] == NULL)
4313 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4314 if (values2[j] == NULL)
4315 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
4316 ret = xmlStrEqual(values1[i], values2[j]);
4317 if (ret)
4318 break;
4319 }
Owen Taylor3473f882001-02-23 17:55:21 +00004320 }
4321 if (ret)
4322 break;
4323 }
4324 for (i = 0;i < ns1->nodeNr;i++)
4325 if (values1[i] != NULL)
4326 xmlFree(values1[i]);
4327 for (j = 0;j < ns2->nodeNr;j++)
4328 if (values2[j] != NULL)
4329 xmlFree(values2[j]);
4330 xmlFree(values1);
4331 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004332 xmlFree(hashs1);
4333 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004334 return(ret);
4335}
4336
4337/**
4338 * xmlXPathEqualValues:
4339 * @ctxt: the XPath Parser context
4340 *
4341 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4342 *
4343 * Returns 0 or 1 depending on the results of the test.
4344 */
4345int
4346xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4347 xmlXPathObjectPtr arg1, arg2;
4348 int ret = 0;
4349
4350 arg1 = valuePop(ctxt);
4351 if (arg1 == NULL)
4352 XP_ERROR0(XPATH_INVALID_OPERAND);
4353
4354 arg2 = valuePop(ctxt);
4355 if (arg2 == NULL) {
4356 xmlXPathFreeObject(arg1);
4357 XP_ERROR0(XPATH_INVALID_OPERAND);
4358 }
4359
4360 if (arg1 == arg2) {
4361#ifdef DEBUG_EXPR
4362 xmlGenericError(xmlGenericErrorContext,
4363 "Equal: by pointer\n");
4364#endif
4365 return(1);
4366 }
4367
4368 switch (arg1->type) {
4369 case XPATH_UNDEFINED:
4370#ifdef DEBUG_EXPR
4371 xmlGenericError(xmlGenericErrorContext,
4372 "Equal: undefined\n");
4373#endif
4374 break;
4375 case XPATH_XSLT_TREE:
4376 case XPATH_NODESET:
4377 switch (arg2->type) {
4378 case XPATH_UNDEFINED:
4379#ifdef DEBUG_EXPR
4380 xmlGenericError(xmlGenericErrorContext,
4381 "Equal: undefined\n");
4382#endif
4383 break;
4384 case XPATH_XSLT_TREE:
4385 case XPATH_NODESET:
4386 ret = xmlXPathEqualNodeSets(arg1, arg2);
4387 break;
4388 case XPATH_BOOLEAN:
4389 if ((arg1->nodesetval == NULL) ||
4390 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4391 else
4392 ret = 1;
4393 ret = (ret == arg2->boolval);
4394 break;
4395 case XPATH_NUMBER:
4396 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
4397 break;
4398 case XPATH_STRING:
4399 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
4400 break;
4401 case XPATH_USERS:
4402 case XPATH_POINT:
4403 case XPATH_RANGE:
4404 case XPATH_LOCATIONSET:
4405 TODO
4406 break;
4407 }
4408 break;
4409 case XPATH_BOOLEAN:
4410 switch (arg2->type) {
4411 case XPATH_UNDEFINED:
4412#ifdef DEBUG_EXPR
4413 xmlGenericError(xmlGenericErrorContext,
4414 "Equal: undefined\n");
4415#endif
4416 break;
4417 case XPATH_NODESET:
4418 case XPATH_XSLT_TREE:
4419 if ((arg2->nodesetval == NULL) ||
4420 (arg2->nodesetval->nodeNr == 0)) ret = 0;
4421 else
4422 ret = 1;
4423 break;
4424 case XPATH_BOOLEAN:
4425#ifdef DEBUG_EXPR
4426 xmlGenericError(xmlGenericErrorContext,
4427 "Equal: %d boolean %d \n",
4428 arg1->boolval, arg2->boolval);
4429#endif
4430 ret = (arg1->boolval == arg2->boolval);
4431 break;
4432 case XPATH_NUMBER:
4433 if (arg2->floatval) ret = 1;
4434 else ret = 0;
4435 ret = (arg1->boolval == ret);
4436 break;
4437 case XPATH_STRING:
4438 if ((arg2->stringval == NULL) ||
4439 (arg2->stringval[0] == 0)) ret = 0;
4440 else
4441 ret = 1;
4442 ret = (arg1->boolval == ret);
4443 break;
4444 case XPATH_USERS:
4445 case XPATH_POINT:
4446 case XPATH_RANGE:
4447 case XPATH_LOCATIONSET:
4448 TODO
4449 break;
4450 }
4451 break;
4452 case XPATH_NUMBER:
4453 switch (arg2->type) {
4454 case XPATH_UNDEFINED:
4455#ifdef DEBUG_EXPR
4456 xmlGenericError(xmlGenericErrorContext,
4457 "Equal: undefined\n");
4458#endif
4459 break;
4460 case XPATH_NODESET:
4461 case XPATH_XSLT_TREE:
4462 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
4463 break;
4464 case XPATH_BOOLEAN:
4465 if (arg1->floatval) ret = 1;
4466 else ret = 0;
4467 ret = (arg2->boolval == ret);
4468 break;
4469 case XPATH_STRING:
4470 valuePush(ctxt, arg2);
4471 xmlXPathNumberFunction(ctxt, 1);
4472 arg2 = valuePop(ctxt);
4473 /* no break on purpose */
4474 case XPATH_NUMBER:
4475 ret = (arg1->floatval == arg2->floatval);
4476 break;
4477 case XPATH_USERS:
4478 case XPATH_POINT:
4479 case XPATH_RANGE:
4480 case XPATH_LOCATIONSET:
4481 TODO
4482 break;
4483 }
4484 break;
4485 case XPATH_STRING:
4486 switch (arg2->type) {
4487 case XPATH_UNDEFINED:
4488#ifdef DEBUG_EXPR
4489 xmlGenericError(xmlGenericErrorContext,
4490 "Equal: undefined\n");
4491#endif
4492 break;
4493 case XPATH_NODESET:
4494 case XPATH_XSLT_TREE:
4495 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
4496 break;
4497 case XPATH_BOOLEAN:
4498 if ((arg1->stringval == NULL) ||
4499 (arg1->stringval[0] == 0)) ret = 0;
4500 else
4501 ret = 1;
4502 ret = (arg2->boolval == ret);
4503 break;
4504 case XPATH_STRING:
4505 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4506 break;
4507 case XPATH_NUMBER:
4508 valuePush(ctxt, arg1);
4509 xmlXPathNumberFunction(ctxt, 1);
4510 arg1 = valuePop(ctxt);
4511 ret = (arg1->floatval == arg2->floatval);
4512 break;
4513 case XPATH_USERS:
4514 case XPATH_POINT:
4515 case XPATH_RANGE:
4516 case XPATH_LOCATIONSET:
4517 TODO
4518 break;
4519 }
4520 break;
4521 case XPATH_USERS:
4522 case XPATH_POINT:
4523 case XPATH_RANGE:
4524 case XPATH_LOCATIONSET:
4525 TODO
4526 break;
4527 }
4528 xmlXPathFreeObject(arg1);
4529 xmlXPathFreeObject(arg2);
4530 return(ret);
4531}
4532
4533
4534/**
4535 * xmlXPathCompareValues:
4536 * @ctxt: the XPath Parser context
4537 * @inf: less than (1) or greater than (0)
4538 * @strict: is the comparison strict
4539 *
4540 * Implement the compare operation on XPath objects:
4541 * @arg1 < @arg2 (1, 1, ...
4542 * @arg1 <= @arg2 (1, 0, ...
4543 * @arg1 > @arg2 (0, 1, ...
4544 * @arg1 >= @arg2 (0, 0, ...
4545 *
4546 * When neither object to be compared is a node-set and the operator is
4547 * <=, <, >=, >, then the objects are compared by converted both objects
4548 * to numbers and comparing the numbers according to IEEE 754. The <
4549 * comparison will be true if and only if the first number is less than the
4550 * second number. The <= comparison will be true if and only if the first
4551 * number is less than or equal to the second number. The > comparison
4552 * will be true if and only if the first number is greater than the second
4553 * number. The >= comparison will be true if and only if the first number
4554 * is greater than or equal to the second number.
4555 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004556 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00004557 */
4558int
4559xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
4560 int ret = 0;
4561 xmlXPathObjectPtr arg1, arg2;
4562
4563 arg2 = valuePop(ctxt);
4564 if (arg2 == NULL) {
4565 XP_ERROR0(XPATH_INVALID_OPERAND);
4566 }
4567
4568 arg1 = valuePop(ctxt);
4569 if (arg1 == NULL) {
4570 xmlXPathFreeObject(arg2);
4571 XP_ERROR0(XPATH_INVALID_OPERAND);
4572 }
4573
4574 if ((arg2->type == XPATH_NODESET) || (arg1->type == XPATH_NODESET)) {
4575 if ((arg2->type == XPATH_NODESET) && (arg1->type == XPATH_NODESET)) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004576 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004577 } else {
4578 if (arg1->type == XPATH_NODESET) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004579 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
4580 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004581 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004582 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
4583 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00004584 }
4585 }
4586 return(ret);
4587 }
4588
4589 if (arg1->type != XPATH_NUMBER) {
4590 valuePush(ctxt, arg1);
4591 xmlXPathNumberFunction(ctxt, 1);
4592 arg1 = valuePop(ctxt);
4593 }
4594 if (arg1->type != XPATH_NUMBER) {
4595 xmlXPathFreeObject(arg1);
4596 xmlXPathFreeObject(arg2);
4597 XP_ERROR0(XPATH_INVALID_OPERAND);
4598 }
4599 if (arg2->type != XPATH_NUMBER) {
4600 valuePush(ctxt, arg2);
4601 xmlXPathNumberFunction(ctxt, 1);
4602 arg2 = valuePop(ctxt);
4603 }
4604 if (arg2->type != XPATH_NUMBER) {
4605 xmlXPathFreeObject(arg1);
4606 xmlXPathFreeObject(arg2);
4607 XP_ERROR0(XPATH_INVALID_OPERAND);
4608 }
4609 /*
4610 * Add tests for infinity and nan
4611 * => feedback on 3.4 for Inf and NaN
4612 */
4613 if (inf && strict)
4614 ret = (arg1->floatval < arg2->floatval);
4615 else if (inf && !strict)
4616 ret = (arg1->floatval <= arg2->floatval);
4617 else if (!inf && strict)
4618 ret = (arg1->floatval > arg2->floatval);
4619 else if (!inf && !strict)
4620 ret = (arg1->floatval >= arg2->floatval);
4621 xmlXPathFreeObject(arg1);
4622 xmlXPathFreeObject(arg2);
4623 return(ret);
4624}
4625
4626/**
4627 * xmlXPathValueFlipSign:
4628 * @ctxt: the XPath Parser context
4629 *
4630 * Implement the unary - operation on an XPath object
4631 * The numeric operators convert their operands to numbers as if
4632 * by calling the number function.
4633 */
4634void
4635xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004636 CAST_TO_NUMBER;
4637 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00004638 if (ctxt->value->floatval == 0) {
4639 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
4640 ctxt->value->floatval = xmlXPathNZERO;
4641 else
4642 ctxt->value->floatval = 0;
4643 }
4644 else
4645 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00004646}
4647
4648/**
4649 * xmlXPathAddValues:
4650 * @ctxt: the XPath Parser context
4651 *
4652 * Implement the add operation on XPath objects:
4653 * The numeric operators convert their operands to numbers as if
4654 * by calling the number function.
4655 */
4656void
4657xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
4658 xmlXPathObjectPtr arg;
4659 double val;
4660
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004661 arg = valuePop(ctxt);
4662 if (arg == NULL)
4663 XP_ERROR(XPATH_INVALID_OPERAND);
4664 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004665 xmlXPathFreeObject(arg);
4666
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004667 CAST_TO_NUMBER;
4668 CHECK_TYPE(XPATH_NUMBER);
4669 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00004670}
4671
4672/**
4673 * xmlXPathSubValues:
4674 * @ctxt: the XPath Parser context
4675 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004676 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00004677 * The numeric operators convert their operands to numbers as if
4678 * by calling the number function.
4679 */
4680void
4681xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
4682 xmlXPathObjectPtr arg;
4683 double val;
4684
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004685 arg = valuePop(ctxt);
4686 if (arg == NULL)
4687 XP_ERROR(XPATH_INVALID_OPERAND);
4688 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004689 xmlXPathFreeObject(arg);
4690
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004691 CAST_TO_NUMBER;
4692 CHECK_TYPE(XPATH_NUMBER);
4693 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004694}
4695
4696/**
4697 * xmlXPathMultValues:
4698 * @ctxt: the XPath Parser context
4699 *
4700 * Implement the multiply operation on XPath objects:
4701 * The numeric operators convert their operands to numbers as if
4702 * by calling the number function.
4703 */
4704void
4705xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
4706 xmlXPathObjectPtr arg;
4707 double val;
4708
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004709 arg = valuePop(ctxt);
4710 if (arg == NULL)
4711 XP_ERROR(XPATH_INVALID_OPERAND);
4712 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004713 xmlXPathFreeObject(arg);
4714
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004715 CAST_TO_NUMBER;
4716 CHECK_TYPE(XPATH_NUMBER);
4717 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004718}
4719
4720/**
4721 * xmlXPathDivValues:
4722 * @ctxt: the XPath Parser context
4723 *
4724 * Implement the div operation on XPath objects @arg1 / @arg2:
4725 * The numeric operators convert their operands to numbers as if
4726 * by calling the number function.
4727 */
4728void
4729xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
4730 xmlXPathObjectPtr arg;
4731 double val;
4732
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004733 arg = valuePop(ctxt);
4734 if (arg == NULL)
4735 XP_ERROR(XPATH_INVALID_OPERAND);
4736 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004737 xmlXPathFreeObject(arg);
4738
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004739 CAST_TO_NUMBER;
4740 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00004741 if (val == 0 && xmlXPathGetSign(val) == 1) {
4742 if (ctxt->value->floatval == 0)
4743 ctxt->value->floatval = xmlXPathNAN;
4744 else if (ctxt->value->floatval > 0)
4745 ctxt->value->floatval = xmlXPathNINF;
4746 else if (ctxt->value->floatval < 0)
4747 ctxt->value->floatval = xmlXPathPINF;
4748 }
4749 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00004750 if (ctxt->value->floatval == 0)
4751 ctxt->value->floatval = xmlXPathNAN;
4752 else if (ctxt->value->floatval > 0)
4753 ctxt->value->floatval = xmlXPathPINF;
4754 else if (ctxt->value->floatval < 0)
4755 ctxt->value->floatval = xmlXPathNINF;
4756 } else
4757 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004758}
4759
4760/**
4761 * xmlXPathModValues:
4762 * @ctxt: the XPath Parser context
4763 *
4764 * Implement the mod operation on XPath objects: @arg1 / @arg2
4765 * The numeric operators convert their operands to numbers as if
4766 * by calling the number function.
4767 */
4768void
4769xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
4770 xmlXPathObjectPtr arg;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00004771 double arg1, arg2, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00004772
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004773 arg = valuePop(ctxt);
4774 if (arg == NULL)
4775 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00004776 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004777 xmlXPathFreeObject(arg);
4778
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004779 CAST_TO_NUMBER;
4780 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00004781 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00004782 if (arg2 == 0)
4783 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00004784 else {
4785 tmp=arg1/arg2;
4786 ctxt->value->floatval = arg2 * (tmp - (double)((int)tmp));
4787 }
Owen Taylor3473f882001-02-23 17:55:21 +00004788}
4789
4790/************************************************************************
4791 * *
4792 * The traversal functions *
4793 * *
4794 ************************************************************************/
4795
Owen Taylor3473f882001-02-23 17:55:21 +00004796/*
4797 * A traversal function enumerates nodes along an axis.
4798 * Initially it must be called with NULL, and it indicates
4799 * termination on the axis by returning NULL.
4800 */
4801typedef xmlNodePtr (*xmlXPathTraversalFunction)
4802 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
4803
4804/**
4805 * xmlXPathNextSelf:
4806 * @ctxt: the XPath Parser context
4807 * @cur: the current node in the traversal
4808 *
4809 * Traversal function for the "self" direction
4810 * The self axis contains just the context node itself
4811 *
4812 * Returns the next element following that axis
4813 */
4814xmlNodePtr
4815xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4816 if (cur == NULL)
4817 return(ctxt->context->node);
4818 return(NULL);
4819}
4820
4821/**
4822 * xmlXPathNextChild:
4823 * @ctxt: the XPath Parser context
4824 * @cur: the current node in the traversal
4825 *
4826 * Traversal function for the "child" direction
4827 * The child axis contains the children of the context node in document order.
4828 *
4829 * Returns the next element following that axis
4830 */
4831xmlNodePtr
4832xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4833 if (cur == NULL) {
4834 if (ctxt->context->node == NULL) return(NULL);
4835 switch (ctxt->context->node->type) {
4836 case XML_ELEMENT_NODE:
4837 case XML_TEXT_NODE:
4838 case XML_CDATA_SECTION_NODE:
4839 case XML_ENTITY_REF_NODE:
4840 case XML_ENTITY_NODE:
4841 case XML_PI_NODE:
4842 case XML_COMMENT_NODE:
4843 case XML_NOTATION_NODE:
4844 case XML_DTD_NODE:
4845 return(ctxt->context->node->children);
4846 case XML_DOCUMENT_NODE:
4847 case XML_DOCUMENT_TYPE_NODE:
4848 case XML_DOCUMENT_FRAG_NODE:
4849 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004850#ifdef LIBXML_DOCB_ENABLED
4851 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004852#endif
4853 return(((xmlDocPtr) ctxt->context->node)->children);
4854 case XML_ELEMENT_DECL:
4855 case XML_ATTRIBUTE_DECL:
4856 case XML_ENTITY_DECL:
4857 case XML_ATTRIBUTE_NODE:
4858 case XML_NAMESPACE_DECL:
4859 case XML_XINCLUDE_START:
4860 case XML_XINCLUDE_END:
4861 return(NULL);
4862 }
4863 return(NULL);
4864 }
4865 if ((cur->type == XML_DOCUMENT_NODE) ||
4866 (cur->type == XML_HTML_DOCUMENT_NODE))
4867 return(NULL);
4868 return(cur->next);
4869}
4870
4871/**
4872 * xmlXPathNextDescendant:
4873 * @ctxt: the XPath Parser context
4874 * @cur: the current node in the traversal
4875 *
4876 * Traversal function for the "descendant" direction
4877 * the descendant axis contains the descendants of the context node in document
4878 * order; a descendant is a child or a child of a child and so on.
4879 *
4880 * Returns the next element following that axis
4881 */
4882xmlNodePtr
4883xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4884 if (cur == NULL) {
4885 if (ctxt->context->node == NULL)
4886 return(NULL);
4887 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4888 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4889 return(NULL);
4890
4891 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
4892 return(ctxt->context->doc->children);
4893 return(ctxt->context->node->children);
4894 }
4895
Daniel Veillard567e1b42001-08-01 15:53:47 +00004896 if (cur->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004897 if (cur->children->type != XML_ENTITY_DECL)
Daniel Veillard567e1b42001-08-01 15:53:47 +00004898 return(cur->children);
4899 }
4900
4901 if (cur == ctxt->context->node) return(NULL);
4902
Owen Taylor3473f882001-02-23 17:55:21 +00004903 if (cur->next != NULL) return(cur->next);
4904
4905 do {
4906 cur = cur->parent;
4907 if (cur == NULL) return(NULL);
4908 if (cur == ctxt->context->node) return(NULL);
4909 if (cur->next != NULL) {
4910 cur = cur->next;
4911 return(cur);
4912 }
4913 } while (cur != NULL);
4914 return(cur);
4915}
4916
4917/**
4918 * xmlXPathNextDescendantOrSelf:
4919 * @ctxt: the XPath Parser context
4920 * @cur: the current node in the traversal
4921 *
4922 * Traversal function for the "descendant-or-self" direction
4923 * the descendant-or-self axis contains the context node and the descendants
4924 * of the context node in document order; thus the context node is the first
4925 * node on the axis, and the first child of the context node is the second node
4926 * on the axis
4927 *
4928 * Returns the next element following that axis
4929 */
4930xmlNodePtr
4931xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4932 if (cur == NULL) {
4933 if (ctxt->context->node == NULL)
4934 return(NULL);
4935 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4936 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4937 return(NULL);
4938 return(ctxt->context->node);
4939 }
4940
4941 return(xmlXPathNextDescendant(ctxt, cur));
4942}
4943
4944/**
4945 * xmlXPathNextParent:
4946 * @ctxt: the XPath Parser context
4947 * @cur: the current node in the traversal
4948 *
4949 * Traversal function for the "parent" direction
4950 * The parent axis contains the parent of the context node, if there is one.
4951 *
4952 * Returns the next element following that axis
4953 */
4954xmlNodePtr
4955xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4956 /*
4957 * the parent of an attribute or namespace node is the element
4958 * to which the attribute or namespace node is attached
4959 * Namespace handling !!!
4960 */
4961 if (cur == NULL) {
4962 if (ctxt->context->node == NULL) return(NULL);
4963 switch (ctxt->context->node->type) {
4964 case XML_ELEMENT_NODE:
4965 case XML_TEXT_NODE:
4966 case XML_CDATA_SECTION_NODE:
4967 case XML_ENTITY_REF_NODE:
4968 case XML_ENTITY_NODE:
4969 case XML_PI_NODE:
4970 case XML_COMMENT_NODE:
4971 case XML_NOTATION_NODE:
4972 case XML_DTD_NODE:
4973 case XML_ELEMENT_DECL:
4974 case XML_ATTRIBUTE_DECL:
4975 case XML_XINCLUDE_START:
4976 case XML_XINCLUDE_END:
4977 case XML_ENTITY_DECL:
4978 if (ctxt->context->node->parent == NULL)
4979 return((xmlNodePtr) ctxt->context->doc);
4980 return(ctxt->context->node->parent);
4981 case XML_ATTRIBUTE_NODE: {
4982 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
4983
4984 return(att->parent);
4985 }
4986 case XML_DOCUMENT_NODE:
4987 case XML_DOCUMENT_TYPE_NODE:
4988 case XML_DOCUMENT_FRAG_NODE:
4989 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004990#ifdef LIBXML_DOCB_ENABLED
4991 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004992#endif
4993 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004994 case XML_NAMESPACE_DECL: {
4995 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
4996
4997 if ((ns->next != NULL) &&
4998 (ns->next->type != XML_NAMESPACE_DECL))
4999 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005000 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005001 }
Owen Taylor3473f882001-02-23 17:55:21 +00005002 }
5003 }
5004 return(NULL);
5005}
5006
5007/**
5008 * xmlXPathNextAncestor:
5009 * @ctxt: the XPath Parser context
5010 * @cur: the current node in the traversal
5011 *
5012 * Traversal function for the "ancestor" direction
5013 * the ancestor axis contains the ancestors of the context node; the ancestors
5014 * of the context node consist of the parent of context node and the parent's
5015 * parent and so on; the nodes are ordered in reverse document order; thus the
5016 * parent is the first node on the axis, and the parent's parent is the second
5017 * node on the axis
5018 *
5019 * Returns the next element following that axis
5020 */
5021xmlNodePtr
5022xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5023 /*
5024 * the parent of an attribute or namespace node is the element
5025 * to which the attribute or namespace node is attached
5026 * !!!!!!!!!!!!!
5027 */
5028 if (cur == NULL) {
5029 if (ctxt->context->node == NULL) return(NULL);
5030 switch (ctxt->context->node->type) {
5031 case XML_ELEMENT_NODE:
5032 case XML_TEXT_NODE:
5033 case XML_CDATA_SECTION_NODE:
5034 case XML_ENTITY_REF_NODE:
5035 case XML_ENTITY_NODE:
5036 case XML_PI_NODE:
5037 case XML_COMMENT_NODE:
5038 case XML_DTD_NODE:
5039 case XML_ELEMENT_DECL:
5040 case XML_ATTRIBUTE_DECL:
5041 case XML_ENTITY_DECL:
5042 case XML_NOTATION_NODE:
5043 case XML_XINCLUDE_START:
5044 case XML_XINCLUDE_END:
5045 if (ctxt->context->node->parent == NULL)
5046 return((xmlNodePtr) ctxt->context->doc);
5047 return(ctxt->context->node->parent);
5048 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005049 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005050
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005051 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005052 }
5053 case XML_DOCUMENT_NODE:
5054 case XML_DOCUMENT_TYPE_NODE:
5055 case XML_DOCUMENT_FRAG_NODE:
5056 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005057#ifdef LIBXML_DOCB_ENABLED
5058 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005059#endif
5060 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005061 case XML_NAMESPACE_DECL: {
5062 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5063
5064 if ((ns->next != NULL) &&
5065 (ns->next->type != XML_NAMESPACE_DECL))
5066 return((xmlNodePtr) ns->next);
5067 /* Bad, how did that namespace ended-up there ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005068 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005069 }
Owen Taylor3473f882001-02-23 17:55:21 +00005070 }
5071 return(NULL);
5072 }
5073 if (cur == ctxt->context->doc->children)
5074 return((xmlNodePtr) ctxt->context->doc);
5075 if (cur == (xmlNodePtr) ctxt->context->doc)
5076 return(NULL);
5077 switch (cur->type) {
5078 case XML_ELEMENT_NODE:
5079 case XML_TEXT_NODE:
5080 case XML_CDATA_SECTION_NODE:
5081 case XML_ENTITY_REF_NODE:
5082 case XML_ENTITY_NODE:
5083 case XML_PI_NODE:
5084 case XML_COMMENT_NODE:
5085 case XML_NOTATION_NODE:
5086 case XML_DTD_NODE:
5087 case XML_ELEMENT_DECL:
5088 case XML_ATTRIBUTE_DECL:
5089 case XML_ENTITY_DECL:
5090 case XML_XINCLUDE_START:
5091 case XML_XINCLUDE_END:
5092 return(cur->parent);
5093 case XML_ATTRIBUTE_NODE: {
5094 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5095
5096 return(att->parent);
5097 }
5098 case XML_DOCUMENT_NODE:
5099 case XML_DOCUMENT_TYPE_NODE:
5100 case XML_DOCUMENT_FRAG_NODE:
5101 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005102#ifdef LIBXML_DOCB_ENABLED
5103 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005104#endif
5105 return(NULL);
5106 case XML_NAMESPACE_DECL:
5107 /*
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005108 * this should not hapen a namespace can't be
5109 * the ancestor of another node
Owen Taylor3473f882001-02-23 17:55:21 +00005110 */
5111 return(NULL);
5112 }
5113 return(NULL);
5114}
5115
5116/**
5117 * xmlXPathNextAncestorOrSelf:
5118 * @ctxt: the XPath Parser context
5119 * @cur: the current node in the traversal
5120 *
5121 * Traversal function for the "ancestor-or-self" direction
5122 * he ancestor-or-self axis contains the context node and ancestors of
5123 * the context node in reverse document order; thus the context node is
5124 * the first node on the axis, and the context node's parent the second;
5125 * parent here is defined the same as with the parent axis.
5126 *
5127 * Returns the next element following that axis
5128 */
5129xmlNodePtr
5130xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5131 if (cur == NULL)
5132 return(ctxt->context->node);
5133 return(xmlXPathNextAncestor(ctxt, cur));
5134}
5135
5136/**
5137 * xmlXPathNextFollowingSibling:
5138 * @ctxt: the XPath Parser context
5139 * @cur: the current node in the traversal
5140 *
5141 * Traversal function for the "following-sibling" direction
5142 * The following-sibling axis contains the following siblings of the context
5143 * node in document order.
5144 *
5145 * Returns the next element following that axis
5146 */
5147xmlNodePtr
5148xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5149 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5150 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5151 return(NULL);
5152 if (cur == (xmlNodePtr) ctxt->context->doc)
5153 return(NULL);
5154 if (cur == NULL)
5155 return(ctxt->context->node->next);
5156 return(cur->next);
5157}
5158
5159/**
5160 * xmlXPathNextPrecedingSibling:
5161 * @ctxt: the XPath Parser context
5162 * @cur: the current node in the traversal
5163 *
5164 * Traversal function for the "preceding-sibling" direction
5165 * The preceding-sibling axis contains the preceding siblings of the context
5166 * node in reverse document order; the first preceding sibling is first on the
5167 * axis; the sibling preceding that node is the second on the axis and so on.
5168 *
5169 * Returns the next element following that axis
5170 */
5171xmlNodePtr
5172xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5173 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5174 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5175 return(NULL);
5176 if (cur == (xmlNodePtr) ctxt->context->doc)
5177 return(NULL);
5178 if (cur == NULL)
5179 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005180 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5181 cur = cur->prev;
5182 if (cur == NULL)
5183 return(ctxt->context->node->prev);
5184 }
Owen Taylor3473f882001-02-23 17:55:21 +00005185 return(cur->prev);
5186}
5187
5188/**
5189 * xmlXPathNextFollowing:
5190 * @ctxt: the XPath Parser context
5191 * @cur: the current node in the traversal
5192 *
5193 * Traversal function for the "following" direction
5194 * The following axis contains all nodes in the same document as the context
5195 * node that are after the context node in document order, excluding any
5196 * descendants and excluding attribute nodes and namespace nodes; the nodes
5197 * are ordered in document order
5198 *
5199 * Returns the next element following that axis
5200 */
5201xmlNodePtr
5202xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5203 if (cur != NULL && cur->children != NULL)
5204 return cur->children ;
5205 if (cur == NULL) cur = ctxt->context->node;
5206 if (cur == NULL) return(NULL) ; /* ERROR */
5207 if (cur->next != NULL) return(cur->next) ;
5208 do {
5209 cur = cur->parent;
5210 if (cur == NULL) return(NULL);
5211 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5212 if (cur->next != NULL) return(cur->next);
5213 } while (cur != NULL);
5214 return(cur);
5215}
5216
5217/*
5218 * xmlXPathIsAncestor:
5219 * @ancestor: the ancestor node
5220 * @node: the current node
5221 *
5222 * Check that @ancestor is a @node's ancestor
5223 *
5224 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5225 */
5226static int
5227xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5228 if ((ancestor == NULL) || (node == NULL)) return(0);
5229 /* nodes need to be in the same document */
5230 if (ancestor->doc != node->doc) return(0);
5231 /* avoid searching if ancestor or node is the root node */
5232 if (ancestor == (xmlNodePtr) node->doc) return(1);
5233 if (node == (xmlNodePtr) ancestor->doc) return(0);
5234 while (node->parent != NULL) {
5235 if (node->parent == ancestor)
5236 return(1);
5237 node = node->parent;
5238 }
5239 return(0);
5240}
5241
5242/**
5243 * xmlXPathNextPreceding:
5244 * @ctxt: the XPath Parser context
5245 * @cur: the current node in the traversal
5246 *
5247 * Traversal function for the "preceding" direction
5248 * the preceding axis contains all nodes in the same document as the context
5249 * node that are before the context node in document order, excluding any
5250 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5251 * ordered in reverse document order
5252 *
5253 * Returns the next element following that axis
5254 */
5255xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005256xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5257{
Owen Taylor3473f882001-02-23 17:55:21 +00005258 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005259 cur = ctxt->context->node;
5260 if (cur == NULL)
5261 return (NULL);
5262 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5263 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005264 do {
5265 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005266 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5267 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005268 }
5269
5270 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005271 if (cur == NULL)
5272 return (NULL);
5273 if (cur == ctxt->context->doc->children)
5274 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005275 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005276 return (cur);
5277}
5278
5279/**
5280 * xmlXPathNextPrecedingInternal:
5281 * @ctxt: the XPath Parser context
5282 * @cur: the current node in the traversal
5283 *
5284 * Traversal function for the "preceding" direction
5285 * the preceding axis contains all nodes in the same document as the context
5286 * node that are before the context node in document order, excluding any
5287 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5288 * ordered in reverse document order
5289 * This is a faster implementation but internal only since it requires a
5290 * state kept in the parser context: ctxt->ancestor.
5291 *
5292 * Returns the next element following that axis
5293 */
5294static xmlNodePtr
5295xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5296 xmlNodePtr cur)
5297{
5298 if (cur == NULL) {
5299 cur = ctxt->context->node;
5300 if (cur == NULL)
5301 return (NULL);
5302 ctxt->ancestor = cur->parent;
5303 }
5304 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5305 cur = cur->prev;
5306 while (cur->prev == NULL) {
5307 cur = cur->parent;
5308 if (cur == NULL)
5309 return (NULL);
5310 if (cur == ctxt->context->doc->children)
5311 return (NULL);
5312 if (cur != ctxt->ancestor)
5313 return (cur);
5314 ctxt->ancestor = cur->parent;
5315 }
5316 cur = cur->prev;
5317 while (cur->last != NULL)
5318 cur = cur->last;
5319 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005320}
5321
5322/**
5323 * xmlXPathNextNamespace:
5324 * @ctxt: the XPath Parser context
5325 * @cur: the current attribute in the traversal
5326 *
5327 * Traversal function for the "namespace" direction
5328 * the namespace axis contains the namespace nodes of the context node;
5329 * the order of nodes on this axis is implementation-defined; the axis will
5330 * be empty unless the context node is an element
5331 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005332 * We keep the XML namespace node at the end of the list.
5333 *
Owen Taylor3473f882001-02-23 17:55:21 +00005334 * Returns the next element following that axis
5335 */
5336xmlNodePtr
5337xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005338 xmlNodePtr ret;
5339
Owen Taylor3473f882001-02-23 17:55:21 +00005340 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005341 if (cur == (xmlNodePtr) xmlXPathXMLNamespace)
5342 return(NULL);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005343 if ((cur == NULL) || (ctxt->context->tmpNsList == NULL)) {
5344 if (ctxt->context->tmpNsList != NULL)
5345 xmlFree(ctxt->context->tmpNsList);
5346 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005347 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005348 if (ctxt->context->tmpNsList == NULL) return(NULL);
5349 ctxt->context->tmpNsNr = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005350 }
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005351 ret = (xmlNodePtr)ctxt->context->tmpNsList[ctxt->context->tmpNsNr++];
5352 if (ret == NULL) {
5353 xmlFree(ctxt->context->tmpNsList);
5354 ctxt->context->tmpNsList = NULL;
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005355 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005356 }
5357 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005358}
5359
5360/**
5361 * xmlXPathNextAttribute:
5362 * @ctxt: the XPath Parser context
5363 * @cur: the current attribute in the traversal
5364 *
5365 * Traversal function for the "attribute" direction
5366 * TODO: support DTD inherited default attributes
5367 *
5368 * Returns the next element following that axis
5369 */
5370xmlNodePtr
5371xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005372 if (ctxt->context->node == NULL)
5373 return(NULL);
5374 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5375 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005376 if (cur == NULL) {
5377 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5378 return(NULL);
5379 return((xmlNodePtr)ctxt->context->node->properties);
5380 }
5381 return((xmlNodePtr)cur->next);
5382}
5383
5384/************************************************************************
5385 * *
5386 * NodeTest Functions *
5387 * *
5388 ************************************************************************/
5389
Owen Taylor3473f882001-02-23 17:55:21 +00005390#define IS_FUNCTION 200
5391
Owen Taylor3473f882001-02-23 17:55:21 +00005392
5393/************************************************************************
5394 * *
5395 * Implicit tree core function library *
5396 * *
5397 ************************************************************************/
5398
5399/**
5400 * xmlXPathRoot:
5401 * @ctxt: the XPath Parser context
5402 *
5403 * Initialize the context to the root of the document
5404 */
5405void
5406xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5407 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5408 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5409}
5410
5411/************************************************************************
5412 * *
5413 * The explicit core function library *
5414 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5415 * *
5416 ************************************************************************/
5417
5418
5419/**
5420 * xmlXPathLastFunction:
5421 * @ctxt: the XPath Parser context
5422 * @nargs: the number of arguments
5423 *
5424 * Implement the last() XPath function
5425 * number last()
5426 * The last function returns the number of nodes in the context node list.
5427 */
5428void
5429xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5430 CHECK_ARITY(0);
5431 if (ctxt->context->contextSize >= 0) {
5432 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5433#ifdef DEBUG_EXPR
5434 xmlGenericError(xmlGenericErrorContext,
5435 "last() : %d\n", ctxt->context->contextSize);
5436#endif
5437 } else {
5438 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5439 }
5440}
5441
5442/**
5443 * xmlXPathPositionFunction:
5444 * @ctxt: the XPath Parser context
5445 * @nargs: the number of arguments
5446 *
5447 * Implement the position() XPath function
5448 * number position()
5449 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005450 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00005451 * will be equal to last().
5452 */
5453void
5454xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5455 CHECK_ARITY(0);
5456 if (ctxt->context->proximityPosition >= 0) {
5457 valuePush(ctxt,
5458 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5459#ifdef DEBUG_EXPR
5460 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5461 ctxt->context->proximityPosition);
5462#endif
5463 } else {
5464 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5465 }
5466}
5467
5468/**
5469 * xmlXPathCountFunction:
5470 * @ctxt: the XPath Parser context
5471 * @nargs: the number of arguments
5472 *
5473 * Implement the count() XPath function
5474 * number count(node-set)
5475 */
5476void
5477xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5478 xmlXPathObjectPtr cur;
5479
5480 CHECK_ARITY(1);
5481 if ((ctxt->value == NULL) ||
5482 ((ctxt->value->type != XPATH_NODESET) &&
5483 (ctxt->value->type != XPATH_XSLT_TREE)))
5484 XP_ERROR(XPATH_INVALID_TYPE);
5485 cur = valuePop(ctxt);
5486
Daniel Veillard911f49a2001-04-07 15:39:35 +00005487 if ((cur == NULL) || (cur->nodesetval == NULL))
5488 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00005489 else if (cur->type == XPATH_NODESET) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00005490 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00005491 } else {
5492 if ((cur->nodesetval->nodeNr != 1) ||
5493 (cur->nodesetval->nodeTab == NULL)) {
5494 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5495 } else {
5496 xmlNodePtr tmp;
5497 int i = 0;
5498
5499 tmp = cur->nodesetval->nodeTab[0];
5500 if (tmp != NULL) {
5501 tmp = tmp->children;
5502 while (tmp != NULL) {
5503 tmp = tmp->next;
5504 i++;
5505 }
5506 }
5507 valuePush(ctxt, xmlXPathNewFloat((double) i));
5508 }
5509 }
Owen Taylor3473f882001-02-23 17:55:21 +00005510 xmlXPathFreeObject(cur);
5511}
5512
5513/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005514 * xmlXPathGetElementsByIds:
5515 * @doc: the document
5516 * @ids: a whitespace separated list of IDs
5517 *
5518 * Selects elements by their unique ID.
5519 *
5520 * Returns a node-set of selected elements.
5521 */
5522static xmlNodeSetPtr
5523xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5524 xmlNodeSetPtr ret;
5525 const xmlChar *cur = ids;
5526 xmlChar *ID;
5527 xmlAttrPtr attr;
5528 xmlNodePtr elem = NULL;
5529
5530 ret = xmlXPathNodeSetCreate(NULL);
5531
5532 while (IS_BLANK(*cur)) cur++;
5533 while (*cur != 0) {
5534 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
5535 (*cur == '.') || (*cur == '-') ||
5536 (*cur == '_') || (*cur == ':') ||
5537 (IS_COMBINING(*cur)) ||
5538 (IS_EXTENDER(*cur)))
5539 cur++;
5540
5541 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
5542
5543 ID = xmlStrndup(ids, cur - ids);
5544 attr = xmlGetID(doc, ID);
5545 if (attr != NULL) {
5546 elem = attr->parent;
5547 xmlXPathNodeSetAdd(ret, elem);
5548 }
5549 if (ID != NULL)
5550 xmlFree(ID);
5551
5552 while (IS_BLANK(*cur)) cur++;
5553 ids = cur;
5554 }
5555 return(ret);
5556}
5557
5558/**
Owen Taylor3473f882001-02-23 17:55:21 +00005559 * xmlXPathIdFunction:
5560 * @ctxt: the XPath Parser context
5561 * @nargs: the number of arguments
5562 *
5563 * Implement the id() XPath function
5564 * node-set id(object)
5565 * The id function selects elements by their unique ID
5566 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
5567 * then the result is the union of the result of applying id to the
5568 * string value of each of the nodes in the argument node-set. When the
5569 * argument to id is of any other type, the argument is converted to a
5570 * string as if by a call to the string function; the string is split
5571 * into a whitespace-separated list of tokens (whitespace is any sequence
5572 * of characters matching the production S); the result is a node-set
5573 * containing the elements in the same document as the context node that
5574 * have a unique ID equal to any of the tokens in the list.
5575 */
5576void
5577xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005578 xmlChar *tokens;
5579 xmlNodeSetPtr ret;
5580 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00005581
5582 CHECK_ARITY(1);
5583 obj = valuePop(ctxt);
5584 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
5585 if (obj->type == XPATH_NODESET) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005586 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00005587 int i;
5588
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005589 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005590
Daniel Veillard911f49a2001-04-07 15:39:35 +00005591 if (obj->nodesetval != NULL) {
5592 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005593 tokens =
5594 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
5595 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
5596 ret = xmlXPathNodeSetMerge(ret, ns);
5597 xmlXPathFreeNodeSet(ns);
5598 if (tokens != NULL)
5599 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00005600 }
Owen Taylor3473f882001-02-23 17:55:21 +00005601 }
5602
5603 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005604 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005605 return;
5606 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005607 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00005608
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005609 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
5610 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005611
Owen Taylor3473f882001-02-23 17:55:21 +00005612 xmlXPathFreeObject(obj);
5613 return;
5614}
5615
5616/**
5617 * xmlXPathLocalNameFunction:
5618 * @ctxt: the XPath Parser context
5619 * @nargs: the number of arguments
5620 *
5621 * Implement the local-name() XPath function
5622 * string local-name(node-set?)
5623 * The local-name function returns a string containing the local part
5624 * of the name of the node in the argument node-set that is first in
5625 * document order. If the node-set is empty or the first node has no
5626 * name, an empty string is returned. If the argument is omitted it
5627 * defaults to the context node.
5628 */
5629void
5630xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5631 xmlXPathObjectPtr cur;
5632
5633 if (nargs == 0) {
5634 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5635 nargs = 1;
5636 }
5637
5638 CHECK_ARITY(1);
5639 if ((ctxt->value == NULL) ||
5640 ((ctxt->value->type != XPATH_NODESET) &&
5641 (ctxt->value->type != XPATH_XSLT_TREE)))
5642 XP_ERROR(XPATH_INVALID_TYPE);
5643 cur = valuePop(ctxt);
5644
Daniel Veillard911f49a2001-04-07 15:39:35 +00005645 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005646 valuePush(ctxt, xmlXPathNewCString(""));
5647 } else {
5648 int i = 0; /* Should be first in document order !!!!! */
5649 switch (cur->nodesetval->nodeTab[i]->type) {
5650 case XML_ELEMENT_NODE:
5651 case XML_ATTRIBUTE_NODE:
5652 case XML_PI_NODE:
5653 valuePush(ctxt,
5654 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
5655 break;
5656 case XML_NAMESPACE_DECL:
5657 valuePush(ctxt, xmlXPathNewString(
5658 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
5659 break;
5660 default:
5661 valuePush(ctxt, xmlXPathNewCString(""));
5662 }
5663 }
5664 xmlXPathFreeObject(cur);
5665}
5666
5667/**
5668 * xmlXPathNamespaceURIFunction:
5669 * @ctxt: the XPath Parser context
5670 * @nargs: the number of arguments
5671 *
5672 * Implement the namespace-uri() XPath function
5673 * string namespace-uri(node-set?)
5674 * The namespace-uri function returns a string containing the
5675 * namespace URI of the expanded name of the node in the argument
5676 * node-set that is first in document order. If the node-set is empty,
5677 * the first node has no name, or the expanded name has no namespace
5678 * URI, an empty string is returned. If the argument is omitted it
5679 * defaults to the context node.
5680 */
5681void
5682xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5683 xmlXPathObjectPtr cur;
5684
5685 if (nargs == 0) {
5686 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5687 nargs = 1;
5688 }
5689 CHECK_ARITY(1);
5690 if ((ctxt->value == NULL) ||
5691 ((ctxt->value->type != XPATH_NODESET) &&
5692 (ctxt->value->type != XPATH_XSLT_TREE)))
5693 XP_ERROR(XPATH_INVALID_TYPE);
5694 cur = valuePop(ctxt);
5695
Daniel Veillard911f49a2001-04-07 15:39:35 +00005696 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005697 valuePush(ctxt, xmlXPathNewCString(""));
5698 } else {
5699 int i = 0; /* Should be first in document order !!!!! */
5700 switch (cur->nodesetval->nodeTab[i]->type) {
5701 case XML_ELEMENT_NODE:
5702 case XML_ATTRIBUTE_NODE:
5703 if (cur->nodesetval->nodeTab[i]->ns == NULL)
5704 valuePush(ctxt, xmlXPathNewCString(""));
5705 else
5706 valuePush(ctxt, xmlXPathNewString(
5707 cur->nodesetval->nodeTab[i]->ns->href));
5708 break;
5709 default:
5710 valuePush(ctxt, xmlXPathNewCString(""));
5711 }
5712 }
5713 xmlXPathFreeObject(cur);
5714}
5715
5716/**
5717 * xmlXPathNameFunction:
5718 * @ctxt: the XPath Parser context
5719 * @nargs: the number of arguments
5720 *
5721 * Implement the name() XPath function
5722 * string name(node-set?)
5723 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005724 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00005725 * order. The QName must represent the name with respect to the namespace
5726 * declarations in effect on the node whose name is being represented.
5727 * Typically, this will be the form in which the name occurred in the XML
5728 * source. This need not be the case if there are namespace declarations
5729 * in effect on the node that associate multiple prefixes with the same
5730 * namespace. However, an implementation may include information about
5731 * the original prefix in its representation of nodes; in this case, an
5732 * implementation can ensure that the returned string is always the same
5733 * as the QName used in the XML source. If the argument it omitted it
5734 * defaults to the context node.
5735 * Libxml keep the original prefix so the "real qualified name" used is
5736 * returned.
5737 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005738static void
Daniel Veillard04383752001-07-08 14:27:15 +00005739xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
5740{
Owen Taylor3473f882001-02-23 17:55:21 +00005741 xmlXPathObjectPtr cur;
5742
5743 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00005744 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5745 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00005746 }
5747
5748 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00005749 if ((ctxt->value == NULL) ||
5750 ((ctxt->value->type != XPATH_NODESET) &&
5751 (ctxt->value->type != XPATH_XSLT_TREE)))
5752 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00005753 cur = valuePop(ctxt);
5754
Daniel Veillard911f49a2001-04-07 15:39:35 +00005755 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00005756 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00005757 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00005758 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005759
Daniel Veillard04383752001-07-08 14:27:15 +00005760 switch (cur->nodesetval->nodeTab[i]->type) {
5761 case XML_ELEMENT_NODE:
5762 case XML_ATTRIBUTE_NODE:
5763 if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
5764 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL))
5765 valuePush(ctxt,
5766 xmlXPathNewString(cur->nodesetval->
5767 nodeTab[i]->name));
5768
5769 else {
5770 char name[2000];
5771
5772 snprintf(name, sizeof(name), "%s:%s",
5773 (char *) cur->nodesetval->nodeTab[i]->ns->
5774 prefix,
5775 (char *) cur->nodesetval->nodeTab[i]->name);
5776 name[sizeof(name) - 1] = 0;
5777 valuePush(ctxt, xmlXPathNewCString(name));
5778 }
5779 break;
5780 default:
5781 valuePush(ctxt,
5782 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
5783 xmlXPathLocalNameFunction(ctxt, 1);
5784 }
Owen Taylor3473f882001-02-23 17:55:21 +00005785 }
5786 xmlXPathFreeObject(cur);
5787}
5788
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005789
5790/**
Owen Taylor3473f882001-02-23 17:55:21 +00005791 * xmlXPathStringFunction:
5792 * @ctxt: the XPath Parser context
5793 * @nargs: the number of arguments
5794 *
5795 * Implement the string() XPath function
5796 * string string(object?)
5797 * he string function converts an object to a string as follows:
5798 * - A node-set is converted to a string by returning the value of
5799 * the node in the node-set that is first in document order.
5800 * If the node-set is empty, an empty string is returned.
5801 * - A number is converted to a string as follows
5802 * + NaN is converted to the string NaN
5803 * + positive zero is converted to the string 0
5804 * + negative zero is converted to the string 0
5805 * + positive infinity is converted to the string Infinity
5806 * + negative infinity is converted to the string -Infinity
5807 * + if the number is an integer, the number is represented in
5808 * decimal form as a Number with no decimal point and no leading
5809 * zeros, preceded by a minus sign (-) if the number is negative
5810 * + otherwise, the number is represented in decimal form as a
5811 * Number including a decimal point with at least one digit
5812 * before the decimal point and at least one digit after the
5813 * decimal point, preceded by a minus sign (-) if the number
5814 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005815 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00005816 * before the decimal point; beyond the one required digit
5817 * after the decimal point there must be as many, but only as
5818 * many, more digits as are needed to uniquely distinguish the
5819 * number from all other IEEE 754 numeric values.
5820 * - The boolean false value is converted to the string false.
5821 * The boolean true value is converted to the string true.
5822 *
5823 * If the argument is omitted, it defaults to a node-set with the
5824 * context node as its only member.
5825 */
5826void
5827xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5828 xmlXPathObjectPtr cur;
5829
5830 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005831 valuePush(ctxt,
5832 xmlXPathWrapString(
5833 xmlXPathCastNodeToString(ctxt->context->node)));
5834 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005835 }
5836
5837 CHECK_ARITY(1);
5838 cur = valuePop(ctxt);
5839 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005840 cur = xmlXPathConvertString(cur);
5841 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005842}
5843
5844/**
5845 * xmlXPathStringLengthFunction:
5846 * @ctxt: the XPath Parser context
5847 * @nargs: the number of arguments
5848 *
5849 * Implement the string-length() XPath function
5850 * number string-length(string?)
5851 * The string-length returns the number of characters in the string
5852 * (see [3.6 Strings]). If the argument is omitted, it defaults to
5853 * the context node converted to a string, in other words the value
5854 * of the context node.
5855 */
5856void
5857xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5858 xmlXPathObjectPtr cur;
5859
5860 if (nargs == 0) {
5861 if (ctxt->context->node == NULL) {
5862 valuePush(ctxt, xmlXPathNewFloat(0));
5863 } else {
5864 xmlChar *content;
5865
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005866 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00005867 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00005868 xmlFree(content);
5869 }
5870 return;
5871 }
5872 CHECK_ARITY(1);
5873 CAST_TO_STRING;
5874 CHECK_TYPE(XPATH_STRING);
5875 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00005876 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00005877 xmlXPathFreeObject(cur);
5878}
5879
5880/**
5881 * xmlXPathConcatFunction:
5882 * @ctxt: the XPath Parser context
5883 * @nargs: the number of arguments
5884 *
5885 * Implement the concat() XPath function
5886 * string concat(string, string, string*)
5887 * The concat function returns the concatenation of its arguments.
5888 */
5889void
5890xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5891 xmlXPathObjectPtr cur, newobj;
5892 xmlChar *tmp;
5893
5894 if (nargs < 2) {
5895 CHECK_ARITY(2);
5896 }
5897
5898 CAST_TO_STRING;
5899 cur = valuePop(ctxt);
5900 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
5901 xmlXPathFreeObject(cur);
5902 return;
5903 }
5904 nargs--;
5905
5906 while (nargs > 0) {
5907 CAST_TO_STRING;
5908 newobj = valuePop(ctxt);
5909 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
5910 xmlXPathFreeObject(newobj);
5911 xmlXPathFreeObject(cur);
5912 XP_ERROR(XPATH_INVALID_TYPE);
5913 }
5914 tmp = xmlStrcat(newobj->stringval, cur->stringval);
5915 newobj->stringval = cur->stringval;
5916 cur->stringval = tmp;
5917
5918 xmlXPathFreeObject(newobj);
5919 nargs--;
5920 }
5921 valuePush(ctxt, cur);
5922}
5923
5924/**
5925 * xmlXPathContainsFunction:
5926 * @ctxt: the XPath Parser context
5927 * @nargs: the number of arguments
5928 *
5929 * Implement the contains() XPath function
5930 * boolean contains(string, string)
5931 * The contains function returns true if the first argument string
5932 * contains the second argument string, and otherwise returns false.
5933 */
5934void
5935xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5936 xmlXPathObjectPtr hay, needle;
5937
5938 CHECK_ARITY(2);
5939 CAST_TO_STRING;
5940 CHECK_TYPE(XPATH_STRING);
5941 needle = valuePop(ctxt);
5942 CAST_TO_STRING;
5943 hay = valuePop(ctxt);
5944 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
5945 xmlXPathFreeObject(hay);
5946 xmlXPathFreeObject(needle);
5947 XP_ERROR(XPATH_INVALID_TYPE);
5948 }
5949 if (xmlStrstr(hay->stringval, needle->stringval))
5950 valuePush(ctxt, xmlXPathNewBoolean(1));
5951 else
5952 valuePush(ctxt, xmlXPathNewBoolean(0));
5953 xmlXPathFreeObject(hay);
5954 xmlXPathFreeObject(needle);
5955}
5956
5957/**
5958 * xmlXPathStartsWithFunction:
5959 * @ctxt: the XPath Parser context
5960 * @nargs: the number of arguments
5961 *
5962 * Implement the starts-with() XPath function
5963 * boolean starts-with(string, string)
5964 * The starts-with function returns true if the first argument string
5965 * starts with the second argument string, and otherwise returns false.
5966 */
5967void
5968xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5969 xmlXPathObjectPtr hay, needle;
5970 int n;
5971
5972 CHECK_ARITY(2);
5973 CAST_TO_STRING;
5974 CHECK_TYPE(XPATH_STRING);
5975 needle = valuePop(ctxt);
5976 CAST_TO_STRING;
5977 hay = valuePop(ctxt);
5978 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
5979 xmlXPathFreeObject(hay);
5980 xmlXPathFreeObject(needle);
5981 XP_ERROR(XPATH_INVALID_TYPE);
5982 }
5983 n = xmlStrlen(needle->stringval);
5984 if (xmlStrncmp(hay->stringval, needle->stringval, n))
5985 valuePush(ctxt, xmlXPathNewBoolean(0));
5986 else
5987 valuePush(ctxt, xmlXPathNewBoolean(1));
5988 xmlXPathFreeObject(hay);
5989 xmlXPathFreeObject(needle);
5990}
5991
5992/**
5993 * xmlXPathSubstringFunction:
5994 * @ctxt: the XPath Parser context
5995 * @nargs: the number of arguments
5996 *
5997 * Implement the substring() XPath function
5998 * string substring(string, number, number?)
5999 * The substring function returns the substring of the first argument
6000 * starting at the position specified in the second argument with
6001 * length specified in the third argument. For example,
6002 * substring("12345",2,3) returns "234". If the third argument is not
6003 * specified, it returns the substring starting at the position specified
6004 * in the second argument and continuing to the end of the string. For
6005 * example, substring("12345",2) returns "2345". More precisely, each
6006 * character in the string (see [3.6 Strings]) is considered to have a
6007 * numeric position: the position of the first character is 1, the position
6008 * of the second character is 2 and so on. The returned substring contains
6009 * those characters for which the position of the character is greater than
6010 * or equal to the second argument and, if the third argument is specified,
6011 * less than the sum of the second and third arguments; the comparisons
6012 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6013 * - substring("12345", 1.5, 2.6) returns "234"
6014 * - substring("12345", 0, 3) returns "12"
6015 * - substring("12345", 0 div 0, 3) returns ""
6016 * - substring("12345", 1, 0 div 0) returns ""
6017 * - substring("12345", -42, 1 div 0) returns "12345"
6018 * - substring("12345", -1 div 0, 1 div 0) returns ""
6019 */
6020void
6021xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6022 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006023 double le=0, in;
6024 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006025 xmlChar *ret;
6026
Owen Taylor3473f882001-02-23 17:55:21 +00006027 if (nargs < 2) {
6028 CHECK_ARITY(2);
6029 }
6030 if (nargs > 3) {
6031 CHECK_ARITY(3);
6032 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006033 /*
6034 * take care of possible last (position) argument
6035 */
Owen Taylor3473f882001-02-23 17:55:21 +00006036 if (nargs == 3) {
6037 CAST_TO_NUMBER;
6038 CHECK_TYPE(XPATH_NUMBER);
6039 len = valuePop(ctxt);
6040 le = len->floatval;
6041 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006042 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006043
Owen Taylor3473f882001-02-23 17:55:21 +00006044 CAST_TO_NUMBER;
6045 CHECK_TYPE(XPATH_NUMBER);
6046 start = valuePop(ctxt);
6047 in = start->floatval;
6048 xmlXPathFreeObject(start);
6049 CAST_TO_STRING;
6050 CHECK_TYPE(XPATH_STRING);
6051 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006052 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006053
Daniel Veillard97ac1312001-05-30 19:14:17 +00006054 /*
6055 * If last pos not present, calculate last position
6056 */
6057 if (nargs != 3)
6058 le = m;
6059
6060 /*
6061 * To meet our requirements, initial index calculations
6062 * must be done before we convert to integer format
6063 *
6064 * First we normalize indices
6065 */
6066 in -= 1.0;
6067 le += in;
6068 if (in < 0.0)
6069 in = 0.0;
6070 if (le > (double)m)
6071 le = (double)m;
6072
6073 /*
6074 * Now we go to integer form, rounding up
6075 */
Owen Taylor3473f882001-02-23 17:55:21 +00006076 i = (int) in;
6077 if (((double)i) != in) i++;
6078
Owen Taylor3473f882001-02-23 17:55:21 +00006079 l = (int) le;
6080 if (((double)l) != le) l++;
6081
Daniel Veillard97ac1312001-05-30 19:14:17 +00006082 if (l > m) l=m;
Owen Taylor3473f882001-02-23 17:55:21 +00006083
6084 /* number of chars to copy */
6085 l -= i;
6086
Daniel Veillard97ac1312001-05-30 19:14:17 +00006087 ret = xmlUTF8Strsub(str->stringval, i, l);
Owen Taylor3473f882001-02-23 17:55:21 +00006088 if (ret == NULL)
6089 valuePush(ctxt, xmlXPathNewCString(""));
6090 else {
6091 valuePush(ctxt, xmlXPathNewString(ret));
6092 xmlFree(ret);
6093 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006094
Owen Taylor3473f882001-02-23 17:55:21 +00006095 xmlXPathFreeObject(str);
6096}
6097
6098/**
6099 * xmlXPathSubstringBeforeFunction:
6100 * @ctxt: the XPath Parser context
6101 * @nargs: the number of arguments
6102 *
6103 * Implement the substring-before() XPath function
6104 * string substring-before(string, string)
6105 * The substring-before function returns the substring of the first
6106 * argument string that precedes the first occurrence of the second
6107 * argument string in the first argument string, or the empty string
6108 * if the first argument string does not contain the second argument
6109 * string. For example, substring-before("1999/04/01","/") returns 1999.
6110 */
6111void
6112xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6113 xmlXPathObjectPtr str;
6114 xmlXPathObjectPtr find;
6115 xmlBufferPtr target;
6116 const xmlChar *point;
6117 int offset;
6118
6119 CHECK_ARITY(2);
6120 CAST_TO_STRING;
6121 find = valuePop(ctxt);
6122 CAST_TO_STRING;
6123 str = valuePop(ctxt);
6124
6125 target = xmlBufferCreate();
6126 if (target) {
6127 point = xmlStrstr(str->stringval, find->stringval);
6128 if (point) {
6129 offset = (int)(point - str->stringval);
6130 xmlBufferAdd(target, str->stringval, offset);
6131 }
6132 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6133 xmlBufferFree(target);
6134 }
6135
6136 xmlXPathFreeObject(str);
6137 xmlXPathFreeObject(find);
6138}
6139
6140/**
6141 * xmlXPathSubstringAfterFunction:
6142 * @ctxt: the XPath Parser context
6143 * @nargs: the number of arguments
6144 *
6145 * Implement the substring-after() XPath function
6146 * string substring-after(string, string)
6147 * The substring-after function returns the substring of the first
6148 * argument string that follows the first occurrence of the second
6149 * argument string in the first argument string, or the empty stringi
6150 * if the first argument string does not contain the second argument
6151 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6152 * and substring-after("1999/04/01","19") returns 99/04/01.
6153 */
6154void
6155xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6156 xmlXPathObjectPtr str;
6157 xmlXPathObjectPtr find;
6158 xmlBufferPtr target;
6159 const xmlChar *point;
6160 int offset;
6161
6162 CHECK_ARITY(2);
6163 CAST_TO_STRING;
6164 find = valuePop(ctxt);
6165 CAST_TO_STRING;
6166 str = valuePop(ctxt);
6167
6168 target = xmlBufferCreate();
6169 if (target) {
6170 point = xmlStrstr(str->stringval, find->stringval);
6171 if (point) {
6172 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6173 xmlBufferAdd(target, &str->stringval[offset],
6174 xmlStrlen(str->stringval) - offset);
6175 }
6176 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6177 xmlBufferFree(target);
6178 }
6179
6180 xmlXPathFreeObject(str);
6181 xmlXPathFreeObject(find);
6182}
6183
6184/**
6185 * xmlXPathNormalizeFunction:
6186 * @ctxt: the XPath Parser context
6187 * @nargs: the number of arguments
6188 *
6189 * Implement the normalize-space() XPath function
6190 * string normalize-space(string?)
6191 * The normalize-space function returns the argument string with white
6192 * space normalized by stripping leading and trailing whitespace
6193 * and replacing sequences of whitespace characters by a single
6194 * space. Whitespace characters are the same allowed by the S production
6195 * in XML. If the argument is omitted, it defaults to the context
6196 * node converted to a string, in other words the value of the context node.
6197 */
6198void
6199xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6200 xmlXPathObjectPtr obj = NULL;
6201 xmlChar *source = NULL;
6202 xmlBufferPtr target;
6203 xmlChar blank;
6204
6205 if (nargs == 0) {
6206 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006207 valuePush(ctxt,
6208 xmlXPathWrapString(
6209 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006210 nargs = 1;
6211 }
6212
6213 CHECK_ARITY(1);
6214 CAST_TO_STRING;
6215 CHECK_TYPE(XPATH_STRING);
6216 obj = valuePop(ctxt);
6217 source = obj->stringval;
6218
6219 target = xmlBufferCreate();
6220 if (target && source) {
6221
6222 /* Skip leading whitespaces */
6223 while (IS_BLANK(*source))
6224 source++;
6225
6226 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6227 blank = 0;
6228 while (*source) {
6229 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006230 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006231 } else {
6232 if (blank) {
6233 xmlBufferAdd(target, &blank, 1);
6234 blank = 0;
6235 }
6236 xmlBufferAdd(target, source, 1);
6237 }
6238 source++;
6239 }
6240
6241 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6242 xmlBufferFree(target);
6243 }
6244 xmlXPathFreeObject(obj);
6245}
6246
6247/**
6248 * xmlXPathTranslateFunction:
6249 * @ctxt: the XPath Parser context
6250 * @nargs: the number of arguments
6251 *
6252 * Implement the translate() XPath function
6253 * string translate(string, string, string)
6254 * The translate function returns the first argument string with
6255 * occurrences of characters in the second argument string replaced
6256 * by the character at the corresponding position in the third argument
6257 * string. For example, translate("bar","abc","ABC") returns the string
6258 * BAr. If there is a character in the second argument string with no
6259 * character at a corresponding position in the third argument string
6260 * (because the second argument string is longer than the third argument
6261 * string), then occurrences of that character in the first argument
6262 * string are removed. For example, translate("--aaa--","abc-","ABC")
6263 * returns "AAA". If a character occurs more than once in second
6264 * argument string, then the first occurrence determines the replacement
6265 * character. If the third argument string is longer than the second
6266 * argument string, then excess characters are ignored.
6267 */
6268void
6269xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006270 xmlXPathObjectPtr str;
6271 xmlXPathObjectPtr from;
6272 xmlXPathObjectPtr to;
6273 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006274 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006275 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006276 xmlChar *point;
6277 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006278
Daniel Veillarde043ee12001-04-16 14:08:07 +00006279 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006280
Daniel Veillarde043ee12001-04-16 14:08:07 +00006281 CAST_TO_STRING;
6282 to = valuePop(ctxt);
6283 CAST_TO_STRING;
6284 from = valuePop(ctxt);
6285 CAST_TO_STRING;
6286 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006287
Daniel Veillarde043ee12001-04-16 14:08:07 +00006288 target = xmlBufferCreate();
6289 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006290 max = xmlUTF8Strlen(to->stringval);
6291 for (cptr = str->stringval; (ch=*cptr); ) {
6292 offset = xmlUTF8Strloc(from->stringval, cptr);
6293 if (offset >= 0) {
6294 if (offset < max) {
6295 point = xmlUTF8Strpos(to->stringval, offset);
6296 if (point)
6297 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6298 }
6299 } else
6300 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6301
6302 /* Step to next character in input */
6303 cptr++;
6304 if ( ch & 0x80 ) {
6305 /* if not simple ascii, verify proper format */
6306 if ( (ch & 0xc0) != 0xc0 ) {
6307 xmlGenericError(xmlGenericErrorContext,
6308 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6309 break;
6310 }
6311 /* then skip over remaining bytes for this char */
6312 while ( (ch <<= 1) & 0x80 )
6313 if ( (*cptr++ & 0xc0) != 0x80 ) {
6314 xmlGenericError(xmlGenericErrorContext,
6315 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6316 break;
6317 }
6318 if (ch & 0x80) /* must have had error encountered */
6319 break;
6320 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006321 }
Owen Taylor3473f882001-02-23 17:55:21 +00006322 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006323 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6324 xmlBufferFree(target);
6325 xmlXPathFreeObject(str);
6326 xmlXPathFreeObject(from);
6327 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006328}
6329
6330/**
6331 * xmlXPathBooleanFunction:
6332 * @ctxt: the XPath Parser context
6333 * @nargs: the number of arguments
6334 *
6335 * Implement the boolean() XPath function
6336 * boolean boolean(object)
6337 * he boolean function converts its argument to a boolean as follows:
6338 * - a number is true if and only if it is neither positive or
6339 * negative zero nor NaN
6340 * - a node-set is true if and only if it is non-empty
6341 * - a string is true if and only if its length is non-zero
6342 */
6343void
6344xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6345 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006346
6347 CHECK_ARITY(1);
6348 cur = valuePop(ctxt);
6349 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006350 cur = xmlXPathConvertBoolean(cur);
6351 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006352}
6353
6354/**
6355 * xmlXPathNotFunction:
6356 * @ctxt: the XPath Parser context
6357 * @nargs: the number of arguments
6358 *
6359 * Implement the not() XPath function
6360 * boolean not(boolean)
6361 * The not function returns true if its argument is false,
6362 * and false otherwise.
6363 */
6364void
6365xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6366 CHECK_ARITY(1);
6367 CAST_TO_BOOLEAN;
6368 CHECK_TYPE(XPATH_BOOLEAN);
6369 ctxt->value->boolval = ! ctxt->value->boolval;
6370}
6371
6372/**
6373 * xmlXPathTrueFunction:
6374 * @ctxt: the XPath Parser context
6375 * @nargs: the number of arguments
6376 *
6377 * Implement the true() XPath function
6378 * boolean true()
6379 */
6380void
6381xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6382 CHECK_ARITY(0);
6383 valuePush(ctxt, xmlXPathNewBoolean(1));
6384}
6385
6386/**
6387 * xmlXPathFalseFunction:
6388 * @ctxt: the XPath Parser context
6389 * @nargs: the number of arguments
6390 *
6391 * Implement the false() XPath function
6392 * boolean false()
6393 */
6394void
6395xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6396 CHECK_ARITY(0);
6397 valuePush(ctxt, xmlXPathNewBoolean(0));
6398}
6399
6400/**
6401 * xmlXPathLangFunction:
6402 * @ctxt: the XPath Parser context
6403 * @nargs: the number of arguments
6404 *
6405 * Implement the lang() XPath function
6406 * boolean lang(string)
6407 * The lang function returns true or false depending on whether the
6408 * language of the context node as specified by xml:lang attributes
6409 * is the same as or is a sublanguage of the language specified by
6410 * the argument string. The language of the context node is determined
6411 * by the value of the xml:lang attribute on the context node, or, if
6412 * the context node has no xml:lang attribute, by the value of the
6413 * xml:lang attribute on the nearest ancestor of the context node that
6414 * has an xml:lang attribute. If there is no such attribute, then lang
6415 * returns false. If there is such an attribute, then lang returns
6416 * true if the attribute value is equal to the argument ignoring case,
6417 * or if there is some suffix starting with - such that the attribute
6418 * value is equal to the argument ignoring that suffix of the attribute
6419 * value and ignoring case.
6420 */
6421void
6422xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6423 xmlXPathObjectPtr val;
6424 const xmlChar *theLang;
6425 const xmlChar *lang;
6426 int ret = 0;
6427 int i;
6428
6429 CHECK_ARITY(1);
6430 CAST_TO_STRING;
6431 CHECK_TYPE(XPATH_STRING);
6432 val = valuePop(ctxt);
6433 lang = val->stringval;
6434 theLang = xmlNodeGetLang(ctxt->context->node);
6435 if ((theLang != NULL) && (lang != NULL)) {
6436 for (i = 0;lang[i] != 0;i++)
6437 if (toupper(lang[i]) != toupper(theLang[i]))
6438 goto not_equal;
6439 ret = 1;
6440 }
6441not_equal:
6442 xmlXPathFreeObject(val);
6443 valuePush(ctxt, xmlXPathNewBoolean(ret));
6444}
6445
6446/**
6447 * xmlXPathNumberFunction:
6448 * @ctxt: the XPath Parser context
6449 * @nargs: the number of arguments
6450 *
6451 * Implement the number() XPath function
6452 * number number(object?)
6453 */
6454void
6455xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6456 xmlXPathObjectPtr cur;
6457 double res;
6458
6459 if (nargs == 0) {
6460 if (ctxt->context->node == NULL) {
6461 valuePush(ctxt, xmlXPathNewFloat(0.0));
6462 } else {
6463 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6464
6465 res = xmlXPathStringEvalNumber(content);
6466 valuePush(ctxt, xmlXPathNewFloat(res));
6467 xmlFree(content);
6468 }
6469 return;
6470 }
6471
6472 CHECK_ARITY(1);
6473 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006474 cur = xmlXPathConvertNumber(cur);
6475 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006476}
6477
6478/**
6479 * xmlXPathSumFunction:
6480 * @ctxt: the XPath Parser context
6481 * @nargs: the number of arguments
6482 *
6483 * Implement the sum() XPath function
6484 * number sum(node-set)
6485 * The sum function returns the sum of the values of the nodes in
6486 * the argument node-set.
6487 */
6488void
6489xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6490 xmlXPathObjectPtr cur;
6491 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006492 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00006493
6494 CHECK_ARITY(1);
6495 if ((ctxt->value == NULL) ||
6496 ((ctxt->value->type != XPATH_NODESET) &&
6497 (ctxt->value->type != XPATH_XSLT_TREE)))
6498 XP_ERROR(XPATH_INVALID_TYPE);
6499 cur = valuePop(ctxt);
6500
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006501 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006502 valuePush(ctxt, xmlXPathNewFloat(0.0));
6503 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006504 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
6505 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006506 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006507 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00006508 }
6509 xmlXPathFreeObject(cur);
6510}
6511
6512/**
6513 * xmlXPathFloorFunction:
6514 * @ctxt: the XPath Parser context
6515 * @nargs: the number of arguments
6516 *
6517 * Implement the floor() XPath function
6518 * number floor(number)
6519 * The floor function returns the largest (closest to positive infinity)
6520 * number that is not greater than the argument and that is an integer.
6521 */
6522void
6523xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006524 double f;
6525
Owen Taylor3473f882001-02-23 17:55:21 +00006526 CHECK_ARITY(1);
6527 CAST_TO_NUMBER;
6528 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006529
6530 f = (double)((int) ctxt->value->floatval);
6531 if (f != ctxt->value->floatval) {
6532 if (ctxt->value->floatval > 0)
6533 ctxt->value->floatval = f;
6534 else
6535 ctxt->value->floatval = f - 1;
6536 }
Owen Taylor3473f882001-02-23 17:55:21 +00006537}
6538
6539/**
6540 * xmlXPathCeilingFunction:
6541 * @ctxt: the XPath Parser context
6542 * @nargs: the number of arguments
6543 *
6544 * Implement the ceiling() XPath function
6545 * number ceiling(number)
6546 * The ceiling function returns the smallest (closest to negative infinity)
6547 * number that is not less than the argument and that is an integer.
6548 */
6549void
6550xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6551 double f;
6552
6553 CHECK_ARITY(1);
6554 CAST_TO_NUMBER;
6555 CHECK_TYPE(XPATH_NUMBER);
6556
6557#if 0
6558 ctxt->value->floatval = ceil(ctxt->value->floatval);
6559#else
6560 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006561 if (f != ctxt->value->floatval) {
6562 if (ctxt->value->floatval > 0)
6563 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00006564 else {
6565 if (ctxt->value->floatval < 0 && f == 0)
6566 ctxt->value->floatval = xmlXPathNZERO;
6567 else
6568 ctxt->value->floatval = f;
6569 }
6570
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006571 }
Owen Taylor3473f882001-02-23 17:55:21 +00006572#endif
6573}
6574
6575/**
6576 * xmlXPathRoundFunction:
6577 * @ctxt: the XPath Parser context
6578 * @nargs: the number of arguments
6579 *
6580 * Implement the round() XPath function
6581 * number round(number)
6582 * The round function returns the number that is closest to the
6583 * argument and that is an integer. If there are two such numbers,
6584 * then the one that is even is returned.
6585 */
6586void
6587xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6588 double f;
6589
6590 CHECK_ARITY(1);
6591 CAST_TO_NUMBER;
6592 CHECK_TYPE(XPATH_NUMBER);
6593
Daniel Veillardcda96922001-08-21 10:56:31 +00006594 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
6595 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
6596 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00006597 (ctxt->value->floatval == 0.0))
6598 return;
6599
Owen Taylor3473f882001-02-23 17:55:21 +00006600 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006601 if (ctxt->value->floatval < 0) {
6602 if (ctxt->value->floatval < f - 0.5)
6603 ctxt->value->floatval = f - 1;
6604 else
6605 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00006606 if (ctxt->value->floatval == 0)
6607 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006608 } else {
6609 if (ctxt->value->floatval < f + 0.5)
6610 ctxt->value->floatval = f;
6611 else
6612 ctxt->value->floatval = f + 1;
6613 }
Owen Taylor3473f882001-02-23 17:55:21 +00006614}
6615
6616/************************************************************************
6617 * *
6618 * The Parser *
6619 * *
6620 ************************************************************************/
6621
6622/*
6623 * a couple of forward declarations since we use a recursive call based
6624 * implementation.
6625 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006626static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006627static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006628static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006629#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006630static void xmlXPathCompRelLocationPath(xmlXPathParserContextPtr ctxt);
6631#define xmlXPathCompRelativeLocationPath xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00006632#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006633static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006634#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00006635static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
6636 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00006637
6638/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00006639 * xmlXPathCurrentChar:
6640 * @ctxt: the XPath parser context
6641 * @cur: pointer to the beginning of the char
6642 * @len: pointer to the length of the char read
6643 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006644 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00006645 * bytes in the input buffer.
6646 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006647 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00006648 */
6649
6650static int
6651xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
6652 unsigned char c;
6653 unsigned int val;
6654 const xmlChar *cur;
6655
6656 if (ctxt == NULL)
6657 return(0);
6658 cur = ctxt->cur;
6659
6660 /*
6661 * We are supposed to handle UTF8, check it's valid
6662 * From rfc2044: encoding of the Unicode values on UTF-8:
6663 *
6664 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
6665 * 0000 0000-0000 007F 0xxxxxxx
6666 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
6667 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
6668 *
6669 * Check for the 0x110000 limit too
6670 */
6671 c = *cur;
6672 if (c & 0x80) {
6673 if ((cur[1] & 0xc0) != 0x80)
6674 goto encoding_error;
6675 if ((c & 0xe0) == 0xe0) {
6676
6677 if ((cur[2] & 0xc0) != 0x80)
6678 goto encoding_error;
6679 if ((c & 0xf0) == 0xf0) {
6680 if (((c & 0xf8) != 0xf0) ||
6681 ((cur[3] & 0xc0) != 0x80))
6682 goto encoding_error;
6683 /* 4-byte code */
6684 *len = 4;
6685 val = (cur[0] & 0x7) << 18;
6686 val |= (cur[1] & 0x3f) << 12;
6687 val |= (cur[2] & 0x3f) << 6;
6688 val |= cur[3] & 0x3f;
6689 } else {
6690 /* 3-byte code */
6691 *len = 3;
6692 val = (cur[0] & 0xf) << 12;
6693 val |= (cur[1] & 0x3f) << 6;
6694 val |= cur[2] & 0x3f;
6695 }
6696 } else {
6697 /* 2-byte code */
6698 *len = 2;
6699 val = (cur[0] & 0x1f) << 6;
6700 val |= cur[1] & 0x3f;
6701 }
6702 if (!IS_CHAR(val)) {
6703 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
6704 }
6705 return(val);
6706 } else {
6707 /* 1-byte code */
6708 *len = 1;
6709 return((int) *cur);
6710 }
6711encoding_error:
6712 /*
6713 * If we detect an UTF8 error that probably mean that the
6714 * input encoding didn't get properly advertized in the
6715 * declaration header. Report the error and switch the encoding
6716 * to ISO-Latin-1 (if you don't like this policy, just declare the
6717 * encoding !)
6718 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00006719 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00006720 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00006721}
6722
6723/**
Owen Taylor3473f882001-02-23 17:55:21 +00006724 * xmlXPathParseNCName:
6725 * @ctxt: the XPath Parser context
6726 *
6727 * parse an XML namespace non qualified name.
6728 *
6729 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
6730 *
6731 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
6732 * CombiningChar | Extender
6733 *
6734 * Returns the namespace name or NULL
6735 */
6736
6737xmlChar *
6738xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00006739 const xmlChar *in;
6740 xmlChar *ret;
6741 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006742
Daniel Veillard2156a562001-04-28 12:24:34 +00006743 /*
6744 * Accelerator for simple ASCII names
6745 */
6746 in = ctxt->cur;
6747 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6748 ((*in >= 0x41) && (*in <= 0x5A)) ||
6749 (*in == '_')) {
6750 in++;
6751 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6752 ((*in >= 0x41) && (*in <= 0x5A)) ||
6753 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00006754 (*in == '_') || (*in == '.') ||
6755 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00006756 in++;
6757 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
6758 (*in == '[') || (*in == ']') || (*in == ':') ||
6759 (*in == '@') || (*in == '*')) {
6760 count = in - ctxt->cur;
6761 if (count == 0)
6762 return(NULL);
6763 ret = xmlStrndup(ctxt->cur, count);
6764 ctxt->cur = in;
6765 return(ret);
6766 }
6767 }
6768 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00006769}
6770
Daniel Veillard2156a562001-04-28 12:24:34 +00006771
Owen Taylor3473f882001-02-23 17:55:21 +00006772/**
6773 * xmlXPathParseQName:
6774 * @ctxt: the XPath Parser context
6775 * @prefix: a xmlChar **
6776 *
6777 * parse an XML qualified name
6778 *
6779 * [NS 5] QName ::= (Prefix ':')? LocalPart
6780 *
6781 * [NS 6] Prefix ::= NCName
6782 *
6783 * [NS 7] LocalPart ::= NCName
6784 *
6785 * Returns the function returns the local part, and prefix is updated
6786 * to get the Prefix if any.
6787 */
6788
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006789static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006790xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
6791 xmlChar *ret = NULL;
6792
6793 *prefix = NULL;
6794 ret = xmlXPathParseNCName(ctxt);
6795 if (CUR == ':') {
6796 *prefix = ret;
6797 NEXT;
6798 ret = xmlXPathParseNCName(ctxt);
6799 }
6800 return(ret);
6801}
6802
6803/**
6804 * xmlXPathParseName:
6805 * @ctxt: the XPath Parser context
6806 *
6807 * parse an XML name
6808 *
6809 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
6810 * CombiningChar | Extender
6811 *
6812 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
6813 *
6814 * Returns the namespace name or NULL
6815 */
6816
6817xmlChar *
6818xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006819 const xmlChar *in;
6820 xmlChar *ret;
6821 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006822
Daniel Veillard61d80a22001-04-27 17:13:01 +00006823 /*
6824 * Accelerator for simple ASCII names
6825 */
6826 in = ctxt->cur;
6827 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6828 ((*in >= 0x41) && (*in <= 0x5A)) ||
6829 (*in == '_') || (*in == ':')) {
6830 in++;
6831 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6832 ((*in >= 0x41) && (*in <= 0x5A)) ||
6833 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00006834 (*in == '_') || (*in == '-') ||
6835 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00006836 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00006837 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006838 count = in - ctxt->cur;
6839 ret = xmlStrndup(ctxt->cur, count);
6840 ctxt->cur = in;
6841 return(ret);
6842 }
6843 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006844 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00006845}
6846
Daniel Veillard61d80a22001-04-27 17:13:01 +00006847static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00006848xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006849 xmlChar buf[XML_MAX_NAMELEN + 5];
6850 int len = 0, l;
6851 int c;
6852
6853 /*
6854 * Handler for more complex cases
6855 */
6856 c = CUR_CHAR(l);
6857 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00006858 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
6859 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00006860 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00006861 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006862 return(NULL);
6863 }
6864
6865 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
6866 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
6867 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00006868 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00006869 (IS_COMBINING(c)) ||
6870 (IS_EXTENDER(c)))) {
6871 COPY_BUF(l,buf,len,c);
6872 NEXTL(l);
6873 c = CUR_CHAR(l);
6874 if (len >= XML_MAX_NAMELEN) {
6875 /*
6876 * Okay someone managed to make a huge name, so he's ready to pay
6877 * for the processing speed.
6878 */
6879 xmlChar *buffer;
6880 int max = len * 2;
6881
6882 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
6883 if (buffer == NULL) {
6884 XP_ERROR0(XPATH_MEMORY_ERROR);
6885 }
6886 memcpy(buffer, buf, len);
6887 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
6888 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00006889 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00006890 (IS_COMBINING(c)) ||
6891 (IS_EXTENDER(c))) {
6892 if (len + 10 > max) {
6893 max *= 2;
6894 buffer = (xmlChar *) xmlRealloc(buffer,
6895 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00006896 if (buffer == NULL) {
6897 XP_ERROR0(XPATH_MEMORY_ERROR);
6898 }
6899 }
6900 COPY_BUF(l,buffer,len,c);
6901 NEXTL(l);
6902 c = CUR_CHAR(l);
6903 }
6904 buffer[len] = 0;
6905 return(buffer);
6906 }
6907 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006908 if (len == 0)
6909 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00006910 return(xmlStrndup(buf, len));
6911}
Owen Taylor3473f882001-02-23 17:55:21 +00006912/**
6913 * xmlXPathStringEvalNumber:
6914 * @str: A string to scan
6915 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00006916 * [30a] Float ::= Number ('e' Digits?)?
6917 *
Owen Taylor3473f882001-02-23 17:55:21 +00006918 * [30] Number ::= Digits ('.' Digits?)?
6919 * | '.' Digits
6920 * [31] Digits ::= [0-9]+
6921 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006922 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00006923 * In complement of the Number expression, this function also handles
6924 * negative values : '-' Number.
6925 *
6926 * Returns the double value.
6927 */
6928double
6929xmlXPathStringEvalNumber(const xmlChar *str) {
6930 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00006931 double ret;
Owen Taylor3473f882001-02-23 17:55:21 +00006932 double mult = 1;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006933 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006934 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006935 int exponent = 0;
6936 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006937#ifdef __GNUC__
6938 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00006939 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006940#endif
Bjorn Reese70a9da52001-04-21 16:57:29 +00006941
Owen Taylor3473f882001-02-23 17:55:21 +00006942 while (IS_BLANK(*cur)) cur++;
6943 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
6944 return(xmlXPathNAN);
6945 }
6946 if (*cur == '-') {
6947 isneg = 1;
6948 cur++;
6949 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00006950
6951#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006952 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00006953 * tmp/temp is a workaround against a gcc compiler bug
6954 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006955 */
Daniel Veillard7b416132002-03-07 08:36:03 +00006956 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006957 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00006958 ret = ret * 10;
6959 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00006960 ok = 1;
6961 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00006962 temp = (double) tmp;
6963 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00006964 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00006965#else
Daniel Veillard7b416132002-03-07 08:36:03 +00006966 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006967 while ((*cur >= '0') && (*cur <= '9')) {
6968 ret = ret * 10 + (*cur - '0');
6969 ok = 1;
6970 cur++;
6971 }
6972#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006973
Owen Taylor3473f882001-02-23 17:55:21 +00006974 if (*cur == '.') {
6975 cur++;
6976 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
6977 return(xmlXPathNAN);
6978 }
6979 while ((*cur >= '0') && (*cur <= '9')) {
6980 mult /= 10;
6981 ret = ret + (*cur - '0') * mult;
6982 cur++;
6983 }
6984 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00006985 if ((*cur == 'e') || (*cur == 'E')) {
6986 cur++;
6987 if (*cur == '-') {
6988 is_exponent_negative = 1;
6989 cur++;
6990 }
6991 while ((*cur >= '0') && (*cur <= '9')) {
6992 exponent = exponent * 10 + (*cur - '0');
6993 cur++;
6994 }
6995 }
Owen Taylor3473f882001-02-23 17:55:21 +00006996 while (IS_BLANK(*cur)) cur++;
6997 if (*cur != 0) return(xmlXPathNAN);
6998 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006999 if (is_exponent_negative) exponent = -exponent;
7000 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007001 return(ret);
7002}
7003
7004/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007005 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007006 * @ctxt: the XPath Parser context
7007 *
7008 * [30] Number ::= Digits ('.' Digits?)?
7009 * | '.' Digits
7010 * [31] Digits ::= [0-9]+
7011 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007012 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007013 *
7014 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007015static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007016xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7017{
Owen Taylor3473f882001-02-23 17:55:21 +00007018 double ret = 0.0;
7019 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007020 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007021 int exponent = 0;
7022 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007023#ifdef __GNUC__
7024 unsigned long tmp = 0;
7025 double temp;
7026#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007027
7028 CHECK_ERROR;
7029 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7030 XP_ERROR(XPATH_NUMBER_ERROR);
7031 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007032#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007033 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007034 * tmp/temp is a workaround against a gcc compiler bug
7035 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007036 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007037 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007038 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007039 ret = ret * 10;
7040 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007041 ok = 1;
7042 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007043 temp = (double) tmp;
7044 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007045 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007046#else
7047 ret = 0;
7048 while ((CUR >= '0') && (CUR <= '9')) {
7049 ret = ret * 10 + (CUR - '0');
7050 ok = 1;
7051 NEXT;
7052 }
7053#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007054 if (CUR == '.') {
7055 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007056 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7057 XP_ERROR(XPATH_NUMBER_ERROR);
7058 }
7059 while ((CUR >= '0') && (CUR <= '9')) {
7060 mult /= 10;
7061 ret = ret + (CUR - '0') * mult;
7062 NEXT;
7063 }
Owen Taylor3473f882001-02-23 17:55:21 +00007064 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007065 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007066 NEXT;
7067 if (CUR == '-') {
7068 is_exponent_negative = 1;
7069 NEXT;
7070 }
7071 while ((CUR >= '0') && (CUR <= '9')) {
7072 exponent = exponent * 10 + (CUR - '0');
7073 NEXT;
7074 }
7075 if (is_exponent_negative)
7076 exponent = -exponent;
7077 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007078 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007079 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007080 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007081}
7082
7083/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007084 * xmlXPathParseLiteral:
7085 * @ctxt: the XPath Parser context
7086 *
7087 * Parse a Literal
7088 *
7089 * [29] Literal ::= '"' [^"]* '"'
7090 * | "'" [^']* "'"
7091 *
7092 * Returns the value found or NULL in case of error
7093 */
7094static xmlChar *
7095xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7096 const xmlChar *q;
7097 xmlChar *ret = NULL;
7098
7099 if (CUR == '"') {
7100 NEXT;
7101 q = CUR_PTR;
7102 while ((IS_CHAR(CUR)) && (CUR != '"'))
7103 NEXT;
7104 if (!IS_CHAR(CUR)) {
7105 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7106 } else {
7107 ret = xmlStrndup(q, CUR_PTR - q);
7108 NEXT;
7109 }
7110 } else if (CUR == '\'') {
7111 NEXT;
7112 q = CUR_PTR;
7113 while ((IS_CHAR(CUR)) && (CUR != '\''))
7114 NEXT;
7115 if (!IS_CHAR(CUR)) {
7116 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7117 } else {
7118 ret = xmlStrndup(q, CUR_PTR - q);
7119 NEXT;
7120 }
7121 } else {
7122 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7123 }
7124 return(ret);
7125}
7126
7127/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007128 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007129 * @ctxt: the XPath Parser context
7130 *
7131 * Parse a Literal and push it on the stack.
7132 *
7133 * [29] Literal ::= '"' [^"]* '"'
7134 * | "'" [^']* "'"
7135 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007136 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007137 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007138static void
7139xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007140 const xmlChar *q;
7141 xmlChar *ret = NULL;
7142
7143 if (CUR == '"') {
7144 NEXT;
7145 q = CUR_PTR;
7146 while ((IS_CHAR(CUR)) && (CUR != '"'))
7147 NEXT;
7148 if (!IS_CHAR(CUR)) {
7149 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7150 } else {
7151 ret = xmlStrndup(q, CUR_PTR - q);
7152 NEXT;
7153 }
7154 } else if (CUR == '\'') {
7155 NEXT;
7156 q = CUR_PTR;
7157 while ((IS_CHAR(CUR)) && (CUR != '\''))
7158 NEXT;
7159 if (!IS_CHAR(CUR)) {
7160 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7161 } else {
7162 ret = xmlStrndup(q, CUR_PTR - q);
7163 NEXT;
7164 }
7165 } else {
7166 XP_ERROR(XPATH_START_LITERAL_ERROR);
7167 }
7168 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007169 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7170 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007171 xmlFree(ret);
7172}
7173
7174/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007175 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007176 * @ctxt: the XPath Parser context
7177 *
7178 * Parse a VariableReference, evaluate it and push it on the stack.
7179 *
7180 * The variable bindings consist of a mapping from variable names
7181 * to variable values. The value of a variable is an object, which
7182 * of any of the types that are possible for the value of an expression,
7183 * and may also be of additional types not specified here.
7184 *
7185 * Early evaluation is possible since:
7186 * The variable bindings [...] used to evaluate a subexpression are
7187 * always the same as those used to evaluate the containing expression.
7188 *
7189 * [36] VariableReference ::= '$' QName
7190 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007191static void
7192xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007193 xmlChar *name;
7194 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007195
7196 SKIP_BLANKS;
7197 if (CUR != '$') {
7198 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7199 }
7200 NEXT;
7201 name = xmlXPathParseQName(ctxt, &prefix);
7202 if (name == NULL) {
7203 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7204 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007205 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007206 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7207 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007208 SKIP_BLANKS;
7209}
7210
7211/**
7212 * xmlXPathIsNodeType:
7213 * @ctxt: the XPath Parser context
7214 * @name: a name string
7215 *
7216 * Is the name given a NodeType one.
7217 *
7218 * [38] NodeType ::= 'comment'
7219 * | 'text'
7220 * | 'processing-instruction'
7221 * | 'node'
7222 *
7223 * Returns 1 if true 0 otherwise
7224 */
7225int
7226xmlXPathIsNodeType(const xmlChar *name) {
7227 if (name == NULL)
7228 return(0);
7229
Daniel Veillard1971ee22002-01-31 20:29:19 +00007230 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007231 return(1);
7232 if (xmlStrEqual(name, BAD_CAST "text"))
7233 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007234 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007235 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007236 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007237 return(1);
7238 return(0);
7239}
7240
7241/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007242 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007243 * @ctxt: the XPath Parser context
7244 *
7245 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7246 * [17] Argument ::= Expr
7247 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007248 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007249 * pushed on the stack
7250 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007251static void
7252xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007253 xmlChar *name;
7254 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007255 int nbargs = 0;
7256
7257 name = xmlXPathParseQName(ctxt, &prefix);
7258 if (name == NULL) {
7259 XP_ERROR(XPATH_EXPR_ERROR);
7260 }
7261 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007262#ifdef DEBUG_EXPR
7263 if (prefix == NULL)
7264 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7265 name);
7266 else
7267 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7268 prefix, name);
7269#endif
7270
Owen Taylor3473f882001-02-23 17:55:21 +00007271 if (CUR != '(') {
7272 XP_ERROR(XPATH_EXPR_ERROR);
7273 }
7274 NEXT;
7275 SKIP_BLANKS;
7276
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007277 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007278 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007279 int op1 = ctxt->comp->last;
7280 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007281 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007282 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007283 nbargs++;
7284 if (CUR == ')') break;
7285 if (CUR != ',') {
7286 XP_ERROR(XPATH_EXPR_ERROR);
7287 }
7288 NEXT;
7289 SKIP_BLANKS;
7290 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007291 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7292 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007293 NEXT;
7294 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007295}
7296
7297/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007298 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007299 * @ctxt: the XPath Parser context
7300 *
7301 * [15] PrimaryExpr ::= VariableReference
7302 * | '(' Expr ')'
7303 * | Literal
7304 * | Number
7305 * | FunctionCall
7306 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007307 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007308 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007309static void
7310xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007311 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007312 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007313 else if (CUR == '(') {
7314 NEXT;
7315 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007316 xmlXPathCompileExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007317 if (CUR != ')') {
7318 XP_ERROR(XPATH_EXPR_ERROR);
7319 }
7320 NEXT;
7321 SKIP_BLANKS;
7322 } else if (IS_DIGIT(CUR)) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007323 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007324 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007325 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007326 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007327 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007328 }
7329 SKIP_BLANKS;
7330}
7331
7332/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007333 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007334 * @ctxt: the XPath Parser context
7335 *
7336 * [20] FilterExpr ::= PrimaryExpr
7337 * | FilterExpr Predicate
7338 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007339 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007340 * Square brackets are used to filter expressions in the same way that
7341 * they are used in location paths. It is an error if the expression to
7342 * be filtered does not evaluate to a node-set. The context node list
7343 * used for evaluating the expression in square brackets is the node-set
7344 * to be filtered listed in document order.
7345 */
7346
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007347static void
7348xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
7349 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007350 CHECK_ERROR;
7351 SKIP_BLANKS;
7352
7353 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007354 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00007355 SKIP_BLANKS;
7356 }
7357
7358
7359}
7360
7361/**
7362 * xmlXPathScanName:
7363 * @ctxt: the XPath Parser context
7364 *
7365 * Trickery: parse an XML name but without consuming the input flow
7366 * Needed to avoid insanity in the parser state.
7367 *
7368 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7369 * CombiningChar | Extender
7370 *
7371 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7372 *
7373 * [6] Names ::= Name (S Name)*
7374 *
7375 * Returns the Name parsed or NULL
7376 */
7377
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007378static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007379xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7380 xmlChar buf[XML_MAX_NAMELEN];
7381 int len = 0;
7382
7383 SKIP_BLANKS;
7384 if (!IS_LETTER(CUR) && (CUR != '_') &&
7385 (CUR != ':')) {
7386 return(NULL);
7387 }
7388
7389 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7390 (NXT(len) == '.') || (NXT(len) == '-') ||
7391 (NXT(len) == '_') || (NXT(len) == ':') ||
7392 (IS_COMBINING(NXT(len))) ||
7393 (IS_EXTENDER(NXT(len)))) {
7394 buf[len] = NXT(len);
7395 len++;
7396 if (len >= XML_MAX_NAMELEN) {
7397 xmlGenericError(xmlGenericErrorContext,
7398 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
7399 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7400 (NXT(len) == '.') || (NXT(len) == '-') ||
7401 (NXT(len) == '_') || (NXT(len) == ':') ||
7402 (IS_COMBINING(NXT(len))) ||
7403 (IS_EXTENDER(NXT(len))))
7404 len++;
7405 break;
7406 }
7407 }
7408 return(xmlStrndup(buf, len));
7409}
7410
7411/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007412 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007413 * @ctxt: the XPath Parser context
7414 *
7415 * [19] PathExpr ::= LocationPath
7416 * | FilterExpr
7417 * | FilterExpr '/' RelativeLocationPath
7418 * | FilterExpr '//' RelativeLocationPath
7419 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007420 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007421 * The / operator and // operators combine an arbitrary expression
7422 * and a relative location path. It is an error if the expression
7423 * does not evaluate to a node-set.
7424 * The / operator does composition in the same way as when / is
7425 * used in a location path. As in location paths, // is short for
7426 * /descendant-or-self::node()/.
7427 */
7428
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007429static void
7430xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007431 int lc = 1; /* Should we branch to LocationPath ? */
7432 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7433
7434 SKIP_BLANKS;
7435 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
7436 (CUR == '\'') || (CUR == '"')) {
7437 lc = 0;
7438 } else if (CUR == '*') {
7439 /* relative or absolute location path */
7440 lc = 1;
7441 } else if (CUR == '/') {
7442 /* relative or absolute location path */
7443 lc = 1;
7444 } else if (CUR == '@') {
7445 /* relative abbreviated attribute location path */
7446 lc = 1;
7447 } else if (CUR == '.') {
7448 /* relative abbreviated attribute location path */
7449 lc = 1;
7450 } else {
7451 /*
7452 * Problem is finding if we have a name here whether it's:
7453 * - a nodetype
7454 * - a function call in which case it's followed by '('
7455 * - an axis in which case it's followed by ':'
7456 * - a element name
7457 * We do an a priori analysis here rather than having to
7458 * maintain parsed token content through the recursive function
7459 * calls. This looks uglier but makes the code quite easier to
7460 * read/write/debug.
7461 */
7462 SKIP_BLANKS;
7463 name = xmlXPathScanName(ctxt);
7464 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7465#ifdef DEBUG_STEP
7466 xmlGenericError(xmlGenericErrorContext,
7467 "PathExpr: Axis\n");
7468#endif
7469 lc = 1;
7470 xmlFree(name);
7471 } else if (name != NULL) {
7472 int len =xmlStrlen(name);
7473 int blank = 0;
7474
7475
7476 while (NXT(len) != 0) {
7477 if (NXT(len) == '/') {
7478 /* element name */
7479#ifdef DEBUG_STEP
7480 xmlGenericError(xmlGenericErrorContext,
7481 "PathExpr: AbbrRelLocation\n");
7482#endif
7483 lc = 1;
7484 break;
7485 } else if (IS_BLANK(NXT(len))) {
7486 /* skip to next */
7487 blank = 1;
7488 } else if (NXT(len) == ':') {
7489#ifdef DEBUG_STEP
7490 xmlGenericError(xmlGenericErrorContext,
7491 "PathExpr: AbbrRelLocation\n");
7492#endif
7493 lc = 1;
7494 break;
7495 } else if ((NXT(len) == '(')) {
7496 /* Note Type or Function */
7497 if (xmlXPathIsNodeType(name)) {
7498#ifdef DEBUG_STEP
7499 xmlGenericError(xmlGenericErrorContext,
7500 "PathExpr: Type search\n");
7501#endif
7502 lc = 1;
7503 } else {
7504#ifdef DEBUG_STEP
7505 xmlGenericError(xmlGenericErrorContext,
7506 "PathExpr: function call\n");
7507#endif
7508 lc = 0;
7509 }
7510 break;
7511 } else if ((NXT(len) == '[')) {
7512 /* element name */
7513#ifdef DEBUG_STEP
7514 xmlGenericError(xmlGenericErrorContext,
7515 "PathExpr: AbbrRelLocation\n");
7516#endif
7517 lc = 1;
7518 break;
7519 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
7520 (NXT(len) == '=')) {
7521 lc = 1;
7522 break;
7523 } else {
7524 lc = 1;
7525 break;
7526 }
7527 len++;
7528 }
7529 if (NXT(len) == 0) {
7530#ifdef DEBUG_STEP
7531 xmlGenericError(xmlGenericErrorContext,
7532 "PathExpr: AbbrRelLocation\n");
7533#endif
7534 /* element name */
7535 lc = 1;
7536 }
7537 xmlFree(name);
7538 } else {
7539 /* make sure all cases are covered explicitely */
7540 XP_ERROR(XPATH_EXPR_ERROR);
7541 }
7542 }
7543
7544 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007545 if (CUR == '/') {
7546 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
7547 } else {
7548 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007549 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007550 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007551 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007552 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007553 CHECK_ERROR;
7554 if ((CUR == '/') && (NXT(1) == '/')) {
7555 SKIP(2);
7556 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007557
7558 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7559 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
7560 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
7561
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007562 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007563 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007564 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007565 }
7566 }
7567 SKIP_BLANKS;
7568}
7569
7570/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007571 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007572 * @ctxt: the XPath Parser context
7573 *
7574 * [18] UnionExpr ::= PathExpr
7575 * | UnionExpr '|' PathExpr
7576 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007577 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007578 */
7579
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007580static void
7581xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
7582 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007583 CHECK_ERROR;
7584 SKIP_BLANKS;
7585 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007586 int op1 = ctxt->comp->last;
7587 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007588
7589 NEXT;
7590 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007591 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007592
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007593 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
7594
Owen Taylor3473f882001-02-23 17:55:21 +00007595 SKIP_BLANKS;
7596 }
Owen Taylor3473f882001-02-23 17:55:21 +00007597}
7598
7599/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007600 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007601 * @ctxt: the XPath Parser context
7602 *
7603 * [27] UnaryExpr ::= UnionExpr
7604 * | '-' UnaryExpr
7605 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007606 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007607 */
7608
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007609static void
7610xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007611 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007612 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007613
7614 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00007615 while (CUR == '-') {
7616 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007617 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007618 NEXT;
7619 SKIP_BLANKS;
7620 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007621
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007622 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007623 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007624 if (found) {
7625 if (minus)
7626 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
7627 else
7628 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007629 }
7630}
7631
7632/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007633 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007634 * @ctxt: the XPath Parser context
7635 *
7636 * [26] MultiplicativeExpr ::= UnaryExpr
7637 * | MultiplicativeExpr MultiplyOperator UnaryExpr
7638 * | MultiplicativeExpr 'div' UnaryExpr
7639 * | MultiplicativeExpr 'mod' UnaryExpr
7640 * [34] MultiplyOperator ::= '*'
7641 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007642 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007643 */
7644
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007645static void
7646xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
7647 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007648 CHECK_ERROR;
7649 SKIP_BLANKS;
7650 while ((CUR == '*') ||
7651 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
7652 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
7653 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007654 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007655
7656 if (CUR == '*') {
7657 op = 0;
7658 NEXT;
7659 } else if (CUR == 'd') {
7660 op = 1;
7661 SKIP(3);
7662 } else if (CUR == 'm') {
7663 op = 2;
7664 SKIP(3);
7665 }
7666 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007667 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007668 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007669 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007670 SKIP_BLANKS;
7671 }
7672}
7673
7674/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007675 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007676 * @ctxt: the XPath Parser context
7677 *
7678 * [25] AdditiveExpr ::= MultiplicativeExpr
7679 * | AdditiveExpr '+' MultiplicativeExpr
7680 * | AdditiveExpr '-' MultiplicativeExpr
7681 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007682 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007683 */
7684
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007685static void
7686xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007687
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007688 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007689 CHECK_ERROR;
7690 SKIP_BLANKS;
7691 while ((CUR == '+') || (CUR == '-')) {
7692 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007693 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007694
7695 if (CUR == '+') plus = 1;
7696 else plus = 0;
7697 NEXT;
7698 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007699 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007700 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007701 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007702 SKIP_BLANKS;
7703 }
7704}
7705
7706/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007707 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007708 * @ctxt: the XPath Parser context
7709 *
7710 * [24] RelationalExpr ::= AdditiveExpr
7711 * | RelationalExpr '<' AdditiveExpr
7712 * | RelationalExpr '>' AdditiveExpr
7713 * | RelationalExpr '<=' AdditiveExpr
7714 * | RelationalExpr '>=' AdditiveExpr
7715 *
7716 * A <= B > C is allowed ? Answer from James, yes with
7717 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
7718 * which is basically what got implemented.
7719 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007720 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00007721 * on the stack
7722 */
7723
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007724static void
7725xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
7726 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007727 CHECK_ERROR;
7728 SKIP_BLANKS;
7729 while ((CUR == '<') ||
7730 (CUR == '>') ||
7731 ((CUR == '<') && (NXT(1) == '=')) ||
7732 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007733 int inf, strict;
7734 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007735
7736 if (CUR == '<') inf = 1;
7737 else inf = 0;
7738 if (NXT(1) == '=') strict = 0;
7739 else strict = 1;
7740 NEXT;
7741 if (!strict) NEXT;
7742 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007743 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007744 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007745 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00007746 SKIP_BLANKS;
7747 }
7748}
7749
7750/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007751 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007752 * @ctxt: the XPath Parser context
7753 *
7754 * [23] EqualityExpr ::= RelationalExpr
7755 * | EqualityExpr '=' RelationalExpr
7756 * | EqualityExpr '!=' RelationalExpr
7757 *
7758 * A != B != C is allowed ? Answer from James, yes with
7759 * (RelationalExpr = RelationalExpr) = RelationalExpr
7760 * (RelationalExpr != RelationalExpr) != RelationalExpr
7761 * which is basically what got implemented.
7762 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007763 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007764 *
7765 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007766static void
7767xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
7768 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007769 CHECK_ERROR;
7770 SKIP_BLANKS;
7771 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007772 int eq;
7773 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007774
7775 if (CUR == '=') eq = 1;
7776 else eq = 0;
7777 NEXT;
7778 if (!eq) NEXT;
7779 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007780 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007781 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007782 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007783 SKIP_BLANKS;
7784 }
7785}
7786
7787/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007788 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007789 * @ctxt: the XPath Parser context
7790 *
7791 * [22] AndExpr ::= EqualityExpr
7792 * | AndExpr 'and' EqualityExpr
7793 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007794 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007795 *
7796 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007797static void
7798xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
7799 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007800 CHECK_ERROR;
7801 SKIP_BLANKS;
7802 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007803 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007804 SKIP(3);
7805 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007806 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007807 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007808 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007809 SKIP_BLANKS;
7810 }
7811}
7812
7813/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007814 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007815 * @ctxt: the XPath Parser context
7816 *
7817 * [14] Expr ::= OrExpr
7818 * [21] OrExpr ::= AndExpr
7819 * | OrExpr 'or' AndExpr
7820 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007821 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00007822 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007823static void
7824xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
7825 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007826 CHECK_ERROR;
7827 SKIP_BLANKS;
7828 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007829 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007830 SKIP(2);
7831 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007832 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007833 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007834 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
7835 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00007836 SKIP_BLANKS;
7837 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007838 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
7839 /* more ops could be optimized too */
7840 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
7841 }
Owen Taylor3473f882001-02-23 17:55:21 +00007842}
7843
7844/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007845 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00007846 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007847 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00007848 *
7849 * [8] Predicate ::= '[' PredicateExpr ']'
7850 * [9] PredicateExpr ::= Expr
7851 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007852 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00007853 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007854static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007855xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007856 int op1 = ctxt->comp->last;
7857
7858 SKIP_BLANKS;
7859 if (CUR != '[') {
7860 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7861 }
7862 NEXT;
7863 SKIP_BLANKS;
7864
7865 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007866 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007867 CHECK_ERROR;
7868
7869 if (CUR != ']') {
7870 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7871 }
7872
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007873 if (filter)
7874 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
7875 else
7876 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007877
7878 NEXT;
7879 SKIP_BLANKS;
7880}
7881
7882/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007883 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00007884 * @ctxt: the XPath Parser context
7885 * @test: pointer to a xmlXPathTestVal
7886 * @type: pointer to a xmlXPathTypeVal
7887 * @prefix: placeholder for a possible name prefix
7888 *
7889 * [7] NodeTest ::= NameTest
7890 * | NodeType '(' ')'
7891 * | 'processing-instruction' '(' Literal ')'
7892 *
7893 * [37] NameTest ::= '*'
7894 * | NCName ':' '*'
7895 * | QName
7896 * [38] NodeType ::= 'comment'
7897 * | 'text'
7898 * | 'processing-instruction'
7899 * | 'node'
7900 *
7901 * Returns the name found and update @test, @type and @prefix appropriately
7902 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007903static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007904xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
7905 xmlXPathTypeVal *type, const xmlChar **prefix,
7906 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00007907 int blanks;
7908
7909 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
7910 STRANGE;
7911 return(NULL);
7912 }
7913 *type = 0;
7914 *test = 0;
7915 *prefix = NULL;
7916 SKIP_BLANKS;
7917
7918 if ((name == NULL) && (CUR == '*')) {
7919 /*
7920 * All elements
7921 */
7922 NEXT;
7923 *test = NODE_TEST_ALL;
7924 return(NULL);
7925 }
7926
7927 if (name == NULL)
7928 name = xmlXPathParseNCName(ctxt);
7929 if (name == NULL) {
7930 XP_ERROR0(XPATH_EXPR_ERROR);
7931 }
7932
7933 blanks = IS_BLANK(CUR);
7934 SKIP_BLANKS;
7935 if (CUR == '(') {
7936 NEXT;
7937 /*
7938 * NodeType or PI search
7939 */
7940 if (xmlStrEqual(name, BAD_CAST "comment"))
7941 *type = NODE_TYPE_COMMENT;
7942 else if (xmlStrEqual(name, BAD_CAST "node"))
7943 *type = NODE_TYPE_NODE;
7944 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
7945 *type = NODE_TYPE_PI;
7946 else if (xmlStrEqual(name, BAD_CAST "text"))
7947 *type = NODE_TYPE_TEXT;
7948 else {
7949 if (name != NULL)
7950 xmlFree(name);
7951 XP_ERROR0(XPATH_EXPR_ERROR);
7952 }
7953
7954 *test = NODE_TEST_TYPE;
7955
7956 SKIP_BLANKS;
7957 if (*type == NODE_TYPE_PI) {
7958 /*
7959 * Specific case: search a PI by name.
7960 */
Owen Taylor3473f882001-02-23 17:55:21 +00007961 if (name != NULL)
7962 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00007963 name = NULL;
7964 if (CUR != ')') {
7965 name = xmlXPathParseLiteral(ctxt);
7966 CHECK_ERROR 0;
7967 SKIP_BLANKS;
7968 }
Owen Taylor3473f882001-02-23 17:55:21 +00007969 }
7970 if (CUR != ')') {
7971 if (name != NULL)
7972 xmlFree(name);
7973 XP_ERROR0(XPATH_UNCLOSED_ERROR);
7974 }
7975 NEXT;
7976 return(name);
7977 }
7978 *test = NODE_TEST_NAME;
7979 if ((!blanks) && (CUR == ':')) {
7980 NEXT;
7981
7982 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007983 * Since currently the parser context don't have a
7984 * namespace list associated:
7985 * The namespace name for this prefix can be computed
7986 * only at evaluation time. The compilation is done
7987 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00007988 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007989#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00007990 *prefix = xmlXPathNsLookup(ctxt->context, name);
7991 if (name != NULL)
7992 xmlFree(name);
7993 if (*prefix == NULL) {
7994 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
7995 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007996#else
7997 *prefix = name;
7998#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007999
8000 if (CUR == '*') {
8001 /*
8002 * All elements
8003 */
8004 NEXT;
8005 *test = NODE_TEST_ALL;
8006 return(NULL);
8007 }
8008
8009 name = xmlXPathParseNCName(ctxt);
8010 if (name == NULL) {
8011 XP_ERROR0(XPATH_EXPR_ERROR);
8012 }
8013 }
8014 return(name);
8015}
8016
8017/**
8018 * xmlXPathIsAxisName:
8019 * @name: a preparsed name token
8020 *
8021 * [6] AxisName ::= 'ancestor'
8022 * | 'ancestor-or-self'
8023 * | 'attribute'
8024 * | 'child'
8025 * | 'descendant'
8026 * | 'descendant-or-self'
8027 * | 'following'
8028 * | 'following-sibling'
8029 * | 'namespace'
8030 * | 'parent'
8031 * | 'preceding'
8032 * | 'preceding-sibling'
8033 * | 'self'
8034 *
8035 * Returns the axis or 0
8036 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008037static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008038xmlXPathIsAxisName(const xmlChar *name) {
8039 xmlXPathAxisVal ret = 0;
8040 switch (name[0]) {
8041 case 'a':
8042 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8043 ret = AXIS_ANCESTOR;
8044 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8045 ret = AXIS_ANCESTOR_OR_SELF;
8046 if (xmlStrEqual(name, BAD_CAST "attribute"))
8047 ret = AXIS_ATTRIBUTE;
8048 break;
8049 case 'c':
8050 if (xmlStrEqual(name, BAD_CAST "child"))
8051 ret = AXIS_CHILD;
8052 break;
8053 case 'd':
8054 if (xmlStrEqual(name, BAD_CAST "descendant"))
8055 ret = AXIS_DESCENDANT;
8056 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8057 ret = AXIS_DESCENDANT_OR_SELF;
8058 break;
8059 case 'f':
8060 if (xmlStrEqual(name, BAD_CAST "following"))
8061 ret = AXIS_FOLLOWING;
8062 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8063 ret = AXIS_FOLLOWING_SIBLING;
8064 break;
8065 case 'n':
8066 if (xmlStrEqual(name, BAD_CAST "namespace"))
8067 ret = AXIS_NAMESPACE;
8068 break;
8069 case 'p':
8070 if (xmlStrEqual(name, BAD_CAST "parent"))
8071 ret = AXIS_PARENT;
8072 if (xmlStrEqual(name, BAD_CAST "preceding"))
8073 ret = AXIS_PRECEDING;
8074 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8075 ret = AXIS_PRECEDING_SIBLING;
8076 break;
8077 case 's':
8078 if (xmlStrEqual(name, BAD_CAST "self"))
8079 ret = AXIS_SELF;
8080 break;
8081 }
8082 return(ret);
8083}
8084
8085/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008086 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008087 * @ctxt: the XPath Parser context
8088 *
8089 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8090 * | AbbreviatedStep
8091 *
8092 * [12] AbbreviatedStep ::= '.' | '..'
8093 *
8094 * [5] AxisSpecifier ::= AxisName '::'
8095 * | AbbreviatedAxisSpecifier
8096 *
8097 * [13] AbbreviatedAxisSpecifier ::= '@'?
8098 *
8099 * Modified for XPtr range support as:
8100 *
8101 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8102 * | AbbreviatedStep
8103 * | 'range-to' '(' Expr ')' Predicate*
8104 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008105 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008106 * A location step of . is short for self::node(). This is
8107 * particularly useful in conjunction with //. For example, the
8108 * location path .//para is short for
8109 * self::node()/descendant-or-self::node()/child::para
8110 * and so will select all para descendant elements of the context
8111 * node.
8112 * Similarly, a location step of .. is short for parent::node().
8113 * For example, ../title is short for parent::node()/child::title
8114 * and so will select the title children of the parent of the context
8115 * node.
8116 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008117static void
8118xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008119#ifdef LIBXML_XPTR_ENABLED
8120 int rangeto = 0;
8121 int op2 = -1;
8122#endif
8123
Owen Taylor3473f882001-02-23 17:55:21 +00008124 SKIP_BLANKS;
8125 if ((CUR == '.') && (NXT(1) == '.')) {
8126 SKIP(2);
8127 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008128 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8129 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008130 } else if (CUR == '.') {
8131 NEXT;
8132 SKIP_BLANKS;
8133 } else {
8134 xmlChar *name = NULL;
8135 const xmlChar *prefix = NULL;
8136 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008137 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008138 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008139 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008140
8141 /*
8142 * The modification needed for XPointer change to the production
8143 */
8144#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008145 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008146 name = xmlXPathParseNCName(ctxt);
8147 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008148 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008149 xmlFree(name);
8150 SKIP_BLANKS;
8151 if (CUR != '(') {
8152 XP_ERROR(XPATH_EXPR_ERROR);
8153 }
8154 NEXT;
8155 SKIP_BLANKS;
8156
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008157 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008158 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008159 CHECK_ERROR;
8160
8161 SKIP_BLANKS;
8162 if (CUR != ')') {
8163 XP_ERROR(XPATH_EXPR_ERROR);
8164 }
8165 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008166 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008167 goto eval_predicates;
8168 }
8169 }
8170#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008171 if (CUR == '*') {
8172 axis = AXIS_CHILD;
8173 } else {
8174 if (name == NULL)
8175 name = xmlXPathParseNCName(ctxt);
8176 if (name != NULL) {
8177 axis = xmlXPathIsAxisName(name);
8178 if (axis != 0) {
8179 SKIP_BLANKS;
8180 if ((CUR == ':') && (NXT(1) == ':')) {
8181 SKIP(2);
8182 xmlFree(name);
8183 name = NULL;
8184 } else {
8185 /* an element name can conflict with an axis one :-\ */
8186 axis = AXIS_CHILD;
8187 }
Owen Taylor3473f882001-02-23 17:55:21 +00008188 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008189 axis = AXIS_CHILD;
8190 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008191 } else if (CUR == '@') {
8192 NEXT;
8193 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008194 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008195 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008196 }
Owen Taylor3473f882001-02-23 17:55:21 +00008197 }
8198
8199 CHECK_ERROR;
8200
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008201 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008202 if (test == 0)
8203 return;
8204
8205#ifdef DEBUG_STEP
8206 xmlGenericError(xmlGenericErrorContext,
8207 "Basis : computing new set\n");
8208#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008209
Owen Taylor3473f882001-02-23 17:55:21 +00008210#ifdef DEBUG_STEP
8211 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008212 if (ctxt->value == NULL)
8213 xmlGenericError(xmlGenericErrorContext, "no value\n");
8214 else if (ctxt->value->nodesetval == NULL)
8215 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8216 else
8217 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008218#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008219
8220eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008221 op1 = ctxt->comp->last;
8222 ctxt->comp->last = -1;
8223
Owen Taylor3473f882001-02-23 17:55:21 +00008224 SKIP_BLANKS;
8225 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008226 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008227 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008228
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008229#ifdef LIBXML_XPTR_ENABLED
8230 if (rangeto) {
8231 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8232 } else
8233#endif
8234 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8235 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008236
Owen Taylor3473f882001-02-23 17:55:21 +00008237 }
8238#ifdef DEBUG_STEP
8239 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008240 if (ctxt->value == NULL)
8241 xmlGenericError(xmlGenericErrorContext, "no value\n");
8242 else if (ctxt->value->nodesetval == NULL)
8243 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8244 else
8245 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8246 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008247#endif
8248}
8249
8250/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008251 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008252 * @ctxt: the XPath Parser context
8253 *
8254 * [3] RelativeLocationPath ::= Step
8255 * | RelativeLocationPath '/' Step
8256 * | AbbreviatedRelativeLocationPath
8257 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8258 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008259 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008260 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008261static void
Owen Taylor3473f882001-02-23 17:55:21 +00008262#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008263xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008264#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008265xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008266#endif
8267(xmlXPathParserContextPtr ctxt) {
8268 SKIP_BLANKS;
8269 if ((CUR == '/') && (NXT(1) == '/')) {
8270 SKIP(2);
8271 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008272 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8273 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008274 } else if (CUR == '/') {
8275 NEXT;
8276 SKIP_BLANKS;
8277 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008278 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008279 SKIP_BLANKS;
8280 while (CUR == '/') {
8281 if ((CUR == '/') && (NXT(1) == '/')) {
8282 SKIP(2);
8283 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008284 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008285 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008286 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008287 } else if (CUR == '/') {
8288 NEXT;
8289 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008290 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008291 }
8292 SKIP_BLANKS;
8293 }
8294}
8295
8296/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008297 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008298 * @ctxt: the XPath Parser context
8299 *
8300 * [1] LocationPath ::= RelativeLocationPath
8301 * | AbsoluteLocationPath
8302 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8303 * | AbbreviatedAbsoluteLocationPath
8304 * [10] AbbreviatedAbsoluteLocationPath ::=
8305 * '//' RelativeLocationPath
8306 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008307 * Compile a location path
8308 *
Owen Taylor3473f882001-02-23 17:55:21 +00008309 * // is short for /descendant-or-self::node()/. For example,
8310 * //para is short for /descendant-or-self::node()/child::para and
8311 * so will select any para element in the document (even a para element
8312 * that is a document element will be selected by //para since the
8313 * document element node is a child of the root node); div//para is
8314 * short for div/descendant-or-self::node()/child::para and so will
8315 * select all para descendants of div children.
8316 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008317static void
8318xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008319 SKIP_BLANKS;
8320 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008321 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008322 } else {
8323 while (CUR == '/') {
8324 if ((CUR == '/') && (NXT(1) == '/')) {
8325 SKIP(2);
8326 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008327 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8328 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008329 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008330 } else if (CUR == '/') {
8331 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008332 SKIP_BLANKS;
8333 if ((CUR != 0 ) &&
8334 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
8335 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008336 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008337 }
8338 }
8339 }
8340}
8341
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008342/************************************************************************
8343 * *
8344 * XPath precompiled expression evaluation *
8345 * *
8346 ************************************************************************/
8347
Daniel Veillardf06307e2001-07-03 10:35:50 +00008348static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008349xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8350
8351/**
8352 * xmlXPathNodeCollectAndTest:
8353 * @ctxt: the XPath Parser context
8354 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008355 * @first: pointer to the first element in document order
8356 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008357 *
8358 * This is the function implementing a step: based on the current list
8359 * of nodes, it builds up a new list, looking at all nodes under that
8360 * axis and selecting them it also do the predicate filtering
8361 *
8362 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00008363 *
8364 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008365 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008366static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008367xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008368 xmlXPathStepOpPtr op,
8369 xmlNodePtr * first, xmlNodePtr * last)
8370{
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008371 xmlXPathAxisVal axis = op->value;
8372 xmlXPathTestVal test = op->value2;
8373 xmlXPathTypeVal type = op->value3;
8374 const xmlChar *prefix = op->value4;
8375 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008376 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008377
8378#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008379 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008380#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008381 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008382 xmlNodeSetPtr ret, list;
8383 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008384 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00008385 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008386 xmlNodePtr cur = NULL;
8387 xmlXPathObjectPtr obj;
8388 xmlNodeSetPtr nodelist;
8389 xmlNodePtr tmp;
8390
Daniel Veillardf06307e2001-07-03 10:35:50 +00008391 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008392 obj = valuePop(ctxt);
8393 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00008394 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008395 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008396 URI = xmlXPathNsLookup(ctxt->context, prefix);
8397 if (URI == NULL)
8398 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008399 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008400#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008401 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008402#endif
8403 switch (axis) {
8404 case AXIS_ANCESTOR:
8405#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008406 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008407#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008408 first = NULL;
8409 next = xmlXPathNextAncestor;
8410 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008411 case AXIS_ANCESTOR_OR_SELF:
8412#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008413 xmlGenericError(xmlGenericErrorContext,
8414 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008415#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008416 first = NULL;
8417 next = xmlXPathNextAncestorOrSelf;
8418 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008419 case AXIS_ATTRIBUTE:
8420#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008421 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008422#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008423 first = NULL;
8424 last = NULL;
8425 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00008426 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008427 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008428 case AXIS_CHILD:
8429#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008430 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008431#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008432 last = NULL;
8433 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00008434 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008435 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008436 case AXIS_DESCENDANT:
8437#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008438 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008439#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008440 last = NULL;
8441 next = xmlXPathNextDescendant;
8442 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008443 case AXIS_DESCENDANT_OR_SELF:
8444#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008445 xmlGenericError(xmlGenericErrorContext,
8446 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008447#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008448 last = NULL;
8449 next = xmlXPathNextDescendantOrSelf;
8450 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008451 case AXIS_FOLLOWING:
8452#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008453 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008454#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008455 last = NULL;
8456 next = xmlXPathNextFollowing;
8457 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008458 case AXIS_FOLLOWING_SIBLING:
8459#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008460 xmlGenericError(xmlGenericErrorContext,
8461 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008462#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008463 last = NULL;
8464 next = xmlXPathNextFollowingSibling;
8465 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008466 case AXIS_NAMESPACE:
8467#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008468 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008469#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008470 first = NULL;
8471 last = NULL;
8472 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00008473 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008474 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008475 case AXIS_PARENT:
8476#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008477 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008478#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008479 first = NULL;
8480 next = xmlXPathNextParent;
8481 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008482 case AXIS_PRECEDING:
8483#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008484 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008485#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008486 first = NULL;
8487 next = xmlXPathNextPrecedingInternal;
8488 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008489 case AXIS_PRECEDING_SIBLING:
8490#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008491 xmlGenericError(xmlGenericErrorContext,
8492 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008493#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008494 first = NULL;
8495 next = xmlXPathNextPrecedingSibling;
8496 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008497 case AXIS_SELF:
8498#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008499 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008500#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008501 first = NULL;
8502 last = NULL;
8503 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00008504 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008505 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008506 }
8507 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008508 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008509
8510 nodelist = obj->nodesetval;
8511 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008512 xmlXPathFreeObject(obj);
8513 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8514 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008515 }
8516 addNode = xmlXPathNodeSetAddUnique;
8517 ret = NULL;
8518#ifdef DEBUG_STEP
8519 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008520 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008521 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008522 case NODE_TEST_NONE:
8523 xmlGenericError(xmlGenericErrorContext,
8524 " searching for none !!!\n");
8525 break;
8526 case NODE_TEST_TYPE:
8527 xmlGenericError(xmlGenericErrorContext,
8528 " searching for type %d\n", type);
8529 break;
8530 case NODE_TEST_PI:
8531 xmlGenericError(xmlGenericErrorContext,
8532 " searching for PI !!!\n");
8533 break;
8534 case NODE_TEST_ALL:
8535 xmlGenericError(xmlGenericErrorContext,
8536 " searching for *\n");
8537 break;
8538 case NODE_TEST_NS:
8539 xmlGenericError(xmlGenericErrorContext,
8540 " searching for namespace %s\n",
8541 prefix);
8542 break;
8543 case NODE_TEST_NAME:
8544 xmlGenericError(xmlGenericErrorContext,
8545 " searching for name %s\n", name);
8546 if (prefix != NULL)
8547 xmlGenericError(xmlGenericErrorContext,
8548 " with namespace %s\n", prefix);
8549 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008550 }
8551 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8552#endif
8553 /*
8554 * 2.3 Node Tests
8555 * - For the attribute axis, the principal node type is attribute.
8556 * - For the namespace axis, the principal node type is namespace.
8557 * - For other axes, the principal node type is element.
8558 *
8559 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008560 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008561 * select all element children of the context node
8562 */
8563 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008564 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008565 ctxt->context->node = nodelist->nodeTab[i];
8566
Daniel Veillardf06307e2001-07-03 10:35:50 +00008567 cur = NULL;
8568 list = xmlXPathNodeSetCreate(NULL);
8569 do {
8570 cur = next(ctxt, cur);
8571 if (cur == NULL)
8572 break;
8573 if ((first != NULL) && (*first == cur))
8574 break;
8575 if (((t % 256) == 0) &&
8576 (first != NULL) && (*first != NULL) &&
8577 (xmlXPathCmpNodes(*first, cur) >= 0))
8578 break;
8579 if ((last != NULL) && (*last == cur))
8580 break;
8581 if (((t % 256) == 0) &&
8582 (last != NULL) && (*last != NULL) &&
8583 (xmlXPathCmpNodes(cur, *last) >= 0))
8584 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008585 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008586#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008587 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
8588#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008589 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008590 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008591 ctxt->context->node = tmp;
8592 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008593 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008594 if ((cur->type == type) ||
8595 ((type == NODE_TYPE_NODE) &&
8596 ((cur->type == XML_DOCUMENT_NODE) ||
8597 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8598 (cur->type == XML_ELEMENT_NODE) ||
8599 (cur->type == XML_PI_NODE) ||
8600 (cur->type == XML_COMMENT_NODE) ||
8601 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00008602 (cur->type == XML_TEXT_NODE))) ||
8603 ((type == NODE_TYPE_TEXT) &&
8604 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008605#ifdef DEBUG_STEP
8606 n++;
8607#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008608 addNode(list, cur);
8609 }
8610 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008611 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008612 if (cur->type == XML_PI_NODE) {
8613 if ((name != NULL) &&
8614 (!xmlStrEqual(name, cur->name)))
8615 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008616#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008617 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008618#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008619 addNode(list, cur);
8620 }
8621 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008622 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008623 if (axis == AXIS_ATTRIBUTE) {
8624 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008625#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008626 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008627#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008628 addNode(list, cur);
8629 }
8630 } else if (axis == AXIS_NAMESPACE) {
8631 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008632#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008633 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008634#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008635 xmlXPathNodeSetAddNs(list, ctxt->context->node,
8636 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008637 }
8638 } else {
8639 if (cur->type == XML_ELEMENT_NODE) {
8640 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008641#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008642 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008643#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008644 addNode(list, cur);
8645 } else if ((cur->ns != NULL) &&
8646 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008647#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008648 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008649#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008650 addNode(list, cur);
8651 }
8652 }
8653 }
8654 break;
8655 case NODE_TEST_NS:{
8656 TODO;
8657 break;
8658 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008659 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008660 switch (cur->type) {
8661 case XML_ELEMENT_NODE:
8662 if (xmlStrEqual(name, cur->name)) {
8663 if (prefix == NULL) {
8664 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008665#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008666 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008667#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008668 addNode(list, cur);
8669 }
8670 } else {
8671 if ((cur->ns != NULL) &&
8672 (xmlStrEqual(URI,
8673 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008674#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008675 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008676#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008677 addNode(list, cur);
8678 }
8679 }
8680 }
8681 break;
8682 case XML_ATTRIBUTE_NODE:{
8683 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008684
Daniel Veillardf06307e2001-07-03 10:35:50 +00008685 if (xmlStrEqual(name, attr->name)) {
8686 if (prefix == NULL) {
8687 if ((attr->ns == NULL) ||
8688 (attr->ns->prefix == NULL)) {
8689#ifdef DEBUG_STEP
8690 n++;
8691#endif
8692 addNode(list,
8693 (xmlNodePtr) attr);
8694 }
8695 } else {
8696 if ((attr->ns != NULL) &&
8697 (xmlStrEqual(URI,
8698 attr->ns->
8699 href))) {
8700#ifdef DEBUG_STEP
8701 n++;
8702#endif
8703 addNode(list,
8704 (xmlNodePtr) attr);
8705 }
8706 }
8707 }
8708 break;
8709 }
8710 case XML_NAMESPACE_DECL:
8711 if (cur->type == XML_NAMESPACE_DECL) {
8712 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008713
Daniel Veillardf06307e2001-07-03 10:35:50 +00008714 if ((ns->prefix != NULL) && (name != NULL)
8715 && (xmlStrEqual(ns->prefix, name))) {
8716#ifdef DEBUG_STEP
8717 n++;
8718#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008719 xmlXPathNodeSetAddNs(list,
8720 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008721 }
8722 }
8723 break;
8724 default:
8725 break;
8726 }
8727 break;
8728 break;
8729 }
8730 } while (cur != NULL);
8731
8732 /*
8733 * If there is some predicate filtering do it now
8734 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00008735 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008736 xmlXPathObjectPtr obj2;
8737
8738 valuePush(ctxt, xmlXPathWrapNodeSet(list));
8739 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
8740 CHECK_TYPE0(XPATH_NODESET);
8741 obj2 = valuePop(ctxt);
8742 list = obj2->nodesetval;
8743 obj2->nodesetval = NULL;
8744 xmlXPathFreeObject(obj2);
8745 }
8746 if (ret == NULL) {
8747 ret = list;
8748 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00008749 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008750 xmlXPathFreeNodeSet(list);
8751 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008752 }
8753 ctxt->context->node = tmp;
8754#ifdef DEBUG_STEP
8755 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008756 "\nExamined %d nodes, found %d nodes at that step\n",
8757 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008758#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008759 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00008760 if ((obj->boolval) && (obj->user != NULL)) {
8761 ctxt->value->boolval = 1;
8762 ctxt->value->user = obj->user;
8763 obj->user = NULL;
8764 obj->boolval = 0;
8765 }
8766 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008767 return(t);
8768}
8769
8770/**
8771 * xmlXPathNodeCollectAndTestNth:
8772 * @ctxt: the XPath Parser context
8773 * @op: the XPath precompiled step operation
8774 * @indx: the index to collect
8775 * @first: pointer to the first element in document order
8776 * @last: pointer to the last element in document order
8777 *
8778 * This is the function implementing a step: based on the current list
8779 * of nodes, it builds up a new list, looking at all nodes under that
8780 * axis and selecting them it also do the predicate filtering
8781 *
8782 * Pushes the new NodeSet resulting from the search.
8783 * Returns the number of node traversed
8784 */
8785static int
8786xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
8787 xmlXPathStepOpPtr op, int indx,
8788 xmlNodePtr * first, xmlNodePtr * last)
8789{
8790 xmlXPathAxisVal axis = op->value;
8791 xmlXPathTestVal test = op->value2;
8792 xmlXPathTypeVal type = op->value3;
8793 const xmlChar *prefix = op->value4;
8794 const xmlChar *name = op->value5;
8795 const xmlChar *URI = NULL;
8796 int n = 0, t = 0;
8797
8798 int i;
8799 xmlNodeSetPtr list;
8800 xmlXPathTraversalFunction next = NULL;
8801 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
8802 xmlNodePtr cur = NULL;
8803 xmlXPathObjectPtr obj;
8804 xmlNodeSetPtr nodelist;
8805 xmlNodePtr tmp;
8806
8807 CHECK_TYPE0(XPATH_NODESET);
8808 obj = valuePop(ctxt);
8809 addNode = xmlXPathNodeSetAdd;
8810 if (prefix != NULL) {
8811 URI = xmlXPathNsLookup(ctxt->context, prefix);
8812 if (URI == NULL)
8813 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8814 }
8815#ifdef DEBUG_STEP_NTH
8816 xmlGenericError(xmlGenericErrorContext, "new step : ");
8817 if (first != NULL) {
8818 if (*first != NULL)
8819 xmlGenericError(xmlGenericErrorContext, "first = %s ",
8820 (*first)->name);
8821 else
8822 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
8823 }
8824 if (last != NULL) {
8825 if (*last != NULL)
8826 xmlGenericError(xmlGenericErrorContext, "last = %s ",
8827 (*last)->name);
8828 else
8829 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
8830 }
8831#endif
8832 switch (axis) {
8833 case AXIS_ANCESTOR:
8834#ifdef DEBUG_STEP_NTH
8835 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
8836#endif
8837 first = NULL;
8838 next = xmlXPathNextAncestor;
8839 break;
8840 case AXIS_ANCESTOR_OR_SELF:
8841#ifdef DEBUG_STEP_NTH
8842 xmlGenericError(xmlGenericErrorContext,
8843 "axis 'ancestors-or-self' ");
8844#endif
8845 first = NULL;
8846 next = xmlXPathNextAncestorOrSelf;
8847 break;
8848 case AXIS_ATTRIBUTE:
8849#ifdef DEBUG_STEP_NTH
8850 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
8851#endif
8852 first = NULL;
8853 last = NULL;
8854 next = xmlXPathNextAttribute;
8855 break;
8856 case AXIS_CHILD:
8857#ifdef DEBUG_STEP_NTH
8858 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
8859#endif
8860 last = NULL;
8861 next = xmlXPathNextChild;
8862 break;
8863 case AXIS_DESCENDANT:
8864#ifdef DEBUG_STEP_NTH
8865 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
8866#endif
8867 last = NULL;
8868 next = xmlXPathNextDescendant;
8869 break;
8870 case AXIS_DESCENDANT_OR_SELF:
8871#ifdef DEBUG_STEP_NTH
8872 xmlGenericError(xmlGenericErrorContext,
8873 "axis 'descendant-or-self' ");
8874#endif
8875 last = NULL;
8876 next = xmlXPathNextDescendantOrSelf;
8877 break;
8878 case AXIS_FOLLOWING:
8879#ifdef DEBUG_STEP_NTH
8880 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
8881#endif
8882 last = NULL;
8883 next = xmlXPathNextFollowing;
8884 break;
8885 case AXIS_FOLLOWING_SIBLING:
8886#ifdef DEBUG_STEP_NTH
8887 xmlGenericError(xmlGenericErrorContext,
8888 "axis 'following-siblings' ");
8889#endif
8890 last = NULL;
8891 next = xmlXPathNextFollowingSibling;
8892 break;
8893 case AXIS_NAMESPACE:
8894#ifdef DEBUG_STEP_NTH
8895 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
8896#endif
8897 last = NULL;
8898 first = NULL;
8899 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
8900 break;
8901 case AXIS_PARENT:
8902#ifdef DEBUG_STEP_NTH
8903 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
8904#endif
8905 first = NULL;
8906 next = xmlXPathNextParent;
8907 break;
8908 case AXIS_PRECEDING:
8909#ifdef DEBUG_STEP_NTH
8910 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
8911#endif
8912 first = NULL;
8913 next = xmlXPathNextPrecedingInternal;
8914 break;
8915 case AXIS_PRECEDING_SIBLING:
8916#ifdef DEBUG_STEP_NTH
8917 xmlGenericError(xmlGenericErrorContext,
8918 "axis 'preceding-sibling' ");
8919#endif
8920 first = NULL;
8921 next = xmlXPathNextPrecedingSibling;
8922 break;
8923 case AXIS_SELF:
8924#ifdef DEBUG_STEP_NTH
8925 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
8926#endif
8927 first = NULL;
8928 last = NULL;
8929 next = xmlXPathNextSelf;
8930 break;
8931 }
8932 if (next == NULL)
8933 return(0);
8934
8935 nodelist = obj->nodesetval;
8936 if (nodelist == NULL) {
8937 xmlXPathFreeObject(obj);
8938 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8939 return(0);
8940 }
8941 addNode = xmlXPathNodeSetAddUnique;
8942#ifdef DEBUG_STEP_NTH
8943 xmlGenericError(xmlGenericErrorContext,
8944 " context contains %d nodes\n", nodelist->nodeNr);
8945 switch (test) {
8946 case NODE_TEST_NONE:
8947 xmlGenericError(xmlGenericErrorContext,
8948 " searching for none !!!\n");
8949 break;
8950 case NODE_TEST_TYPE:
8951 xmlGenericError(xmlGenericErrorContext,
8952 " searching for type %d\n", type);
8953 break;
8954 case NODE_TEST_PI:
8955 xmlGenericError(xmlGenericErrorContext,
8956 " searching for PI !!!\n");
8957 break;
8958 case NODE_TEST_ALL:
8959 xmlGenericError(xmlGenericErrorContext,
8960 " searching for *\n");
8961 break;
8962 case NODE_TEST_NS:
8963 xmlGenericError(xmlGenericErrorContext,
8964 " searching for namespace %s\n",
8965 prefix);
8966 break;
8967 case NODE_TEST_NAME:
8968 xmlGenericError(xmlGenericErrorContext,
8969 " searching for name %s\n", name);
8970 if (prefix != NULL)
8971 xmlGenericError(xmlGenericErrorContext,
8972 " with namespace %s\n", prefix);
8973 break;
8974 }
8975 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8976#endif
8977 /*
8978 * 2.3 Node Tests
8979 * - For the attribute axis, the principal node type is attribute.
8980 * - For the namespace axis, the principal node type is namespace.
8981 * - For other axes, the principal node type is element.
8982 *
8983 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008984 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00008985 * select all element children of the context node
8986 */
8987 tmp = ctxt->context->node;
8988 list = xmlXPathNodeSetCreate(NULL);
8989 for (i = 0; i < nodelist->nodeNr; i++) {
8990 ctxt->context->node = nodelist->nodeTab[i];
8991
8992 cur = NULL;
8993 n = 0;
8994 do {
8995 cur = next(ctxt, cur);
8996 if (cur == NULL)
8997 break;
8998 if ((first != NULL) && (*first == cur))
8999 break;
9000 if (((t % 256) == 0) &&
9001 (first != NULL) && (*first != NULL) &&
9002 (xmlXPathCmpNodes(*first, cur) >= 0))
9003 break;
9004 if ((last != NULL) && (*last == cur))
9005 break;
9006 if (((t % 256) == 0) &&
9007 (last != NULL) && (*last != NULL) &&
9008 (xmlXPathCmpNodes(cur, *last) >= 0))
9009 break;
9010 t++;
9011 switch (test) {
9012 case NODE_TEST_NONE:
9013 ctxt->context->node = tmp;
9014 STRANGE return(0);
9015 case NODE_TEST_TYPE:
9016 if ((cur->type == type) ||
9017 ((type == NODE_TYPE_NODE) &&
9018 ((cur->type == XML_DOCUMENT_NODE) ||
9019 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9020 (cur->type == XML_ELEMENT_NODE) ||
9021 (cur->type == XML_PI_NODE) ||
9022 (cur->type == XML_COMMENT_NODE) ||
9023 (cur->type == XML_CDATA_SECTION_NODE) ||
9024 (cur->type == XML_TEXT_NODE)))) {
9025 n++;
9026 if (n == indx)
9027 addNode(list, cur);
9028 }
9029 break;
9030 case NODE_TEST_PI:
9031 if (cur->type == XML_PI_NODE) {
9032 if ((name != NULL) &&
9033 (!xmlStrEqual(name, cur->name)))
9034 break;
9035 n++;
9036 if (n == indx)
9037 addNode(list, cur);
9038 }
9039 break;
9040 case NODE_TEST_ALL:
9041 if (axis == AXIS_ATTRIBUTE) {
9042 if (cur->type == XML_ATTRIBUTE_NODE) {
9043 n++;
9044 if (n == indx)
9045 addNode(list, cur);
9046 }
9047 } else if (axis == AXIS_NAMESPACE) {
9048 if (cur->type == XML_NAMESPACE_DECL) {
9049 n++;
9050 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009051 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9052 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009053 }
9054 } else {
9055 if (cur->type == XML_ELEMENT_NODE) {
9056 if (prefix == NULL) {
9057 n++;
9058 if (n == indx)
9059 addNode(list, cur);
9060 } else if ((cur->ns != NULL) &&
9061 (xmlStrEqual(URI, cur->ns->href))) {
9062 n++;
9063 if (n == indx)
9064 addNode(list, cur);
9065 }
9066 }
9067 }
9068 break;
9069 case NODE_TEST_NS:{
9070 TODO;
9071 break;
9072 }
9073 case NODE_TEST_NAME:
9074 switch (cur->type) {
9075 case XML_ELEMENT_NODE:
9076 if (xmlStrEqual(name, cur->name)) {
9077 if (prefix == NULL) {
9078 if (cur->ns == NULL) {
9079 n++;
9080 if (n == indx)
9081 addNode(list, cur);
9082 }
9083 } else {
9084 if ((cur->ns != NULL) &&
9085 (xmlStrEqual(URI,
9086 cur->ns->href))) {
9087 n++;
9088 if (n == indx)
9089 addNode(list, cur);
9090 }
9091 }
9092 }
9093 break;
9094 case XML_ATTRIBUTE_NODE:{
9095 xmlAttrPtr attr = (xmlAttrPtr) cur;
9096
9097 if (xmlStrEqual(name, attr->name)) {
9098 if (prefix == NULL) {
9099 if ((attr->ns == NULL) ||
9100 (attr->ns->prefix == NULL)) {
9101 n++;
9102 if (n == indx)
9103 addNode(list, cur);
9104 }
9105 } else {
9106 if ((attr->ns != NULL) &&
9107 (xmlStrEqual(URI,
9108 attr->ns->
9109 href))) {
9110 n++;
9111 if (n == indx)
9112 addNode(list, cur);
9113 }
9114 }
9115 }
9116 break;
9117 }
9118 case XML_NAMESPACE_DECL:
9119 if (cur->type == XML_NAMESPACE_DECL) {
9120 xmlNsPtr ns = (xmlNsPtr) cur;
9121
9122 if ((ns->prefix != NULL) && (name != NULL)
9123 && (xmlStrEqual(ns->prefix, name))) {
9124 n++;
9125 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009126 xmlXPathNodeSetAddNs(list,
9127 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009128 }
9129 }
9130 break;
9131 default:
9132 break;
9133 }
9134 break;
9135 break;
9136 }
9137 } while (n < indx);
9138 }
9139 ctxt->context->node = tmp;
9140#ifdef DEBUG_STEP_NTH
9141 xmlGenericError(xmlGenericErrorContext,
9142 "\nExamined %d nodes, found %d nodes at that step\n",
9143 t, list->nodeNr);
9144#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009145 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009146 if ((obj->boolval) && (obj->user != NULL)) {
9147 ctxt->value->boolval = 1;
9148 ctxt->value->user = obj->user;
9149 obj->user = NULL;
9150 obj->boolval = 0;
9151 }
9152 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009153 return(t);
9154}
9155
9156/**
9157 * xmlXPathCompOpEvalFirst:
9158 * @ctxt: the XPath parser context with the compiled expression
9159 * @op: an XPath compiled operation
9160 * @first: the first elem found so far
9161 *
9162 * Evaluate the Precompiled XPath operation searching only the first
9163 * element in document order
9164 *
9165 * Returns the number of examined objects.
9166 */
9167static int
9168xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9169 xmlXPathStepOpPtr op, xmlNodePtr * first)
9170{
9171 int total = 0, cur;
9172 xmlXPathCompExprPtr comp;
9173 xmlXPathObjectPtr arg1, arg2;
9174
Daniel Veillard556c6682001-10-06 09:59:51 +00009175 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009176 comp = ctxt->comp;
9177 switch (op->op) {
9178 case XPATH_OP_END:
9179 return (0);
9180 case XPATH_OP_UNION:
9181 total =
9182 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9183 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009184 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009185 if ((ctxt->value != NULL)
9186 && (ctxt->value->type == XPATH_NODESET)
9187 && (ctxt->value->nodesetval != NULL)
9188 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9189 /*
9190 * limit tree traversing to first node in the result
9191 */
9192 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9193 *first = ctxt->value->nodesetval->nodeTab[0];
9194 }
9195 cur =
9196 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9197 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009198 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009199 CHECK_TYPE0(XPATH_NODESET);
9200 arg2 = valuePop(ctxt);
9201
9202 CHECK_TYPE0(XPATH_NODESET);
9203 arg1 = valuePop(ctxt);
9204
9205 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9206 arg2->nodesetval);
9207 valuePush(ctxt, arg1);
9208 xmlXPathFreeObject(arg2);
9209 /* optimizer */
9210 if (total > cur)
9211 xmlXPathCompSwap(op);
9212 return (total + cur);
9213 case XPATH_OP_ROOT:
9214 xmlXPathRoot(ctxt);
9215 return (0);
9216 case XPATH_OP_NODE:
9217 if (op->ch1 != -1)
9218 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009219 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009220 if (op->ch2 != -1)
9221 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009222 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009223 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9224 return (total);
9225 case XPATH_OP_RESET:
9226 if (op->ch1 != -1)
9227 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009228 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009229 if (op->ch2 != -1)
9230 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009231 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009232 ctxt->context->node = NULL;
9233 return (total);
9234 case XPATH_OP_COLLECT:{
9235 if (op->ch1 == -1)
9236 return (total);
9237
9238 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009239 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009240
9241 /*
9242 * Optimization for [n] selection where n is a number
9243 */
9244 if ((op->ch2 != -1) &&
9245 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9246 (comp->steps[op->ch2].ch1 == -1) &&
9247 (comp->steps[op->ch2].ch2 != -1) &&
9248 (comp->steps[comp->steps[op->ch2].ch2].op ==
9249 XPATH_OP_VALUE)) {
9250 xmlXPathObjectPtr val;
9251
9252 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9253 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9254 int indx = (int) val->floatval;
9255
9256 if (val->floatval == (float) indx) {
9257 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9258 first, NULL);
9259 return (total);
9260 }
9261 }
9262 }
9263 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9264 return (total);
9265 }
9266 case XPATH_OP_VALUE:
9267 valuePush(ctxt,
9268 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9269 return (0);
9270 case XPATH_OP_SORT:
9271 if (op->ch1 != -1)
9272 total +=
9273 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9274 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009275 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009276 if ((ctxt->value != NULL)
9277 && (ctxt->value->type == XPATH_NODESET)
9278 && (ctxt->value->nodesetval != NULL))
9279 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9280 return (total);
9281 default:
9282 return (xmlXPathCompOpEval(ctxt, op));
9283 }
9284}
9285
9286/**
9287 * xmlXPathCompOpEvalLast:
9288 * @ctxt: the XPath parser context with the compiled expression
9289 * @op: an XPath compiled operation
9290 * @last: the last elem found so far
9291 *
9292 * Evaluate the Precompiled XPath operation searching only the last
9293 * element in document order
9294 *
9295 * Returns the number of node traversed
9296 */
9297static int
9298xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9299 xmlNodePtr * last)
9300{
9301 int total = 0, cur;
9302 xmlXPathCompExprPtr comp;
9303 xmlXPathObjectPtr arg1, arg2;
9304
Daniel Veillard556c6682001-10-06 09:59:51 +00009305 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009306 comp = ctxt->comp;
9307 switch (op->op) {
9308 case XPATH_OP_END:
9309 return (0);
9310 case XPATH_OP_UNION:
9311 total =
9312 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009313 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009314 if ((ctxt->value != NULL)
9315 && (ctxt->value->type == XPATH_NODESET)
9316 && (ctxt->value->nodesetval != NULL)
9317 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9318 /*
9319 * limit tree traversing to first node in the result
9320 */
9321 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9322 *last =
9323 ctxt->value->nodesetval->nodeTab[ctxt->value->
9324 nodesetval->nodeNr -
9325 1];
9326 }
9327 cur =
9328 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009329 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009330 if ((ctxt->value != NULL)
9331 && (ctxt->value->type == XPATH_NODESET)
9332 && (ctxt->value->nodesetval != NULL)
9333 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9334 }
9335 CHECK_TYPE0(XPATH_NODESET);
9336 arg2 = valuePop(ctxt);
9337
9338 CHECK_TYPE0(XPATH_NODESET);
9339 arg1 = valuePop(ctxt);
9340
9341 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9342 arg2->nodesetval);
9343 valuePush(ctxt, arg1);
9344 xmlXPathFreeObject(arg2);
9345 /* optimizer */
9346 if (total > cur)
9347 xmlXPathCompSwap(op);
9348 return (total + cur);
9349 case XPATH_OP_ROOT:
9350 xmlXPathRoot(ctxt);
9351 return (0);
9352 case XPATH_OP_NODE:
9353 if (op->ch1 != -1)
9354 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009355 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009356 if (op->ch2 != -1)
9357 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009358 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009359 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9360 return (total);
9361 case XPATH_OP_RESET:
9362 if (op->ch1 != -1)
9363 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009364 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009365 if (op->ch2 != -1)
9366 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009367 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009368 ctxt->context->node = NULL;
9369 return (total);
9370 case XPATH_OP_COLLECT:{
9371 if (op->ch1 == -1)
9372 return (0);
9373
9374 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009375 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009376
9377 /*
9378 * Optimization for [n] selection where n is a number
9379 */
9380 if ((op->ch2 != -1) &&
9381 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9382 (comp->steps[op->ch2].ch1 == -1) &&
9383 (comp->steps[op->ch2].ch2 != -1) &&
9384 (comp->steps[comp->steps[op->ch2].ch2].op ==
9385 XPATH_OP_VALUE)) {
9386 xmlXPathObjectPtr val;
9387
9388 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9389 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9390 int indx = (int) val->floatval;
9391
9392 if (val->floatval == (float) indx) {
9393 total +=
9394 xmlXPathNodeCollectAndTestNth(ctxt, op,
9395 indx, NULL,
9396 last);
9397 return (total);
9398 }
9399 }
9400 }
9401 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9402 return (total);
9403 }
9404 case XPATH_OP_VALUE:
9405 valuePush(ctxt,
9406 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9407 return (0);
9408 case XPATH_OP_SORT:
9409 if (op->ch1 != -1)
9410 total +=
9411 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9412 last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009413 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009414 if ((ctxt->value != NULL)
9415 && (ctxt->value->type == XPATH_NODESET)
9416 && (ctxt->value->nodesetval != NULL))
9417 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9418 return (total);
9419 default:
9420 return (xmlXPathCompOpEval(ctxt, op));
9421 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009422}
9423
Owen Taylor3473f882001-02-23 17:55:21 +00009424/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009425 * xmlXPathCompOpEval:
9426 * @ctxt: the XPath parser context with the compiled expression
9427 * @op: an XPath compiled operation
9428 *
9429 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009430 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009431 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009432static int
9433xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9434{
9435 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009436 int equal, ret;
9437 xmlXPathCompExprPtr comp;
9438 xmlXPathObjectPtr arg1, arg2;
9439
Daniel Veillard556c6682001-10-06 09:59:51 +00009440 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009441 comp = ctxt->comp;
9442 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009443 case XPATH_OP_END:
9444 return (0);
9445 case XPATH_OP_AND:
9446 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009447 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009448 xmlXPathBooleanFunction(ctxt, 1);
9449 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9450 return (total);
9451 arg2 = valuePop(ctxt);
9452 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009453 if (ctxt->error) {
9454 xmlXPathFreeObject(arg2);
9455 return(0);
9456 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009457 xmlXPathBooleanFunction(ctxt, 1);
9458 arg1 = valuePop(ctxt);
9459 arg1->boolval &= arg2->boolval;
9460 valuePush(ctxt, arg1);
9461 xmlXPathFreeObject(arg2);
9462 return (total);
9463 case XPATH_OP_OR:
9464 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009465 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009466 xmlXPathBooleanFunction(ctxt, 1);
9467 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9468 return (total);
9469 arg2 = valuePop(ctxt);
9470 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009471 if (ctxt->error) {
9472 xmlXPathFreeObject(arg2);
9473 return(0);
9474 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009475 xmlXPathBooleanFunction(ctxt, 1);
9476 arg1 = valuePop(ctxt);
9477 arg1->boolval |= arg2->boolval;
9478 valuePush(ctxt, arg1);
9479 xmlXPathFreeObject(arg2);
9480 return (total);
9481 case XPATH_OP_EQUAL:
9482 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009483 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009484 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009485 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009486 equal = xmlXPathEqualValues(ctxt);
9487 if (op->value)
9488 valuePush(ctxt, xmlXPathNewBoolean(equal));
9489 else
9490 valuePush(ctxt, xmlXPathNewBoolean(!equal));
9491 return (total);
9492 case XPATH_OP_CMP:
9493 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009494 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009495 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009496 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009497 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
9498 valuePush(ctxt, xmlXPathNewBoolean(ret));
9499 return (total);
9500 case XPATH_OP_PLUS:
9501 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009502 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009503 if (op->ch2 != -1)
9504 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009505 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009506 if (op->value == 0)
9507 xmlXPathSubValues(ctxt);
9508 else if (op->value == 1)
9509 xmlXPathAddValues(ctxt);
9510 else if (op->value == 2)
9511 xmlXPathValueFlipSign(ctxt);
9512 else if (op->value == 3) {
9513 CAST_TO_NUMBER;
9514 CHECK_TYPE0(XPATH_NUMBER);
9515 }
9516 return (total);
9517 case XPATH_OP_MULT:
9518 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009519 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009520 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009521 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009522 if (op->value == 0)
9523 xmlXPathMultValues(ctxt);
9524 else if (op->value == 1)
9525 xmlXPathDivValues(ctxt);
9526 else if (op->value == 2)
9527 xmlXPathModValues(ctxt);
9528 return (total);
9529 case XPATH_OP_UNION:
9530 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009531 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009532 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009533 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009534 CHECK_TYPE0(XPATH_NODESET);
9535 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009536
Daniel Veillardf06307e2001-07-03 10:35:50 +00009537 CHECK_TYPE0(XPATH_NODESET);
9538 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009539
Daniel Veillardf06307e2001-07-03 10:35:50 +00009540 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9541 arg2->nodesetval);
9542 valuePush(ctxt, arg1);
9543 xmlXPathFreeObject(arg2);
9544 return (total);
9545 case XPATH_OP_ROOT:
9546 xmlXPathRoot(ctxt);
9547 return (total);
9548 case XPATH_OP_NODE:
9549 if (op->ch1 != -1)
9550 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009551 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009552 if (op->ch2 != -1)
9553 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009554 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009555 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9556 return (total);
9557 case XPATH_OP_RESET:
9558 if (op->ch1 != -1)
9559 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009560 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009561 if (op->ch2 != -1)
9562 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009563 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009564 ctxt->context->node = NULL;
9565 return (total);
9566 case XPATH_OP_COLLECT:{
9567 if (op->ch1 == -1)
9568 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009569
Daniel Veillardf06307e2001-07-03 10:35:50 +00009570 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009571 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009572
Daniel Veillardf06307e2001-07-03 10:35:50 +00009573 /*
9574 * Optimization for [n] selection where n is a number
9575 */
9576 if ((op->ch2 != -1) &&
9577 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9578 (comp->steps[op->ch2].ch1 == -1) &&
9579 (comp->steps[op->ch2].ch2 != -1) &&
9580 (comp->steps[comp->steps[op->ch2].ch2].op ==
9581 XPATH_OP_VALUE)) {
9582 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +00009583
Daniel Veillardf06307e2001-07-03 10:35:50 +00009584 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9585 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9586 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009587
Daniel Veillardf06307e2001-07-03 10:35:50 +00009588 if (val->floatval == (float) indx) {
9589 total +=
9590 xmlXPathNodeCollectAndTestNth(ctxt, op,
9591 indx, NULL,
9592 NULL);
9593 return (total);
9594 }
9595 }
9596 }
9597 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
9598 return (total);
9599 }
9600 case XPATH_OP_VALUE:
9601 valuePush(ctxt,
9602 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9603 return (total);
9604 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +00009605 xmlXPathObjectPtr val;
9606
Daniel Veillardf06307e2001-07-03 10:35:50 +00009607 if (op->ch1 != -1)
9608 total +=
9609 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009610 if (op->value5 == NULL) {
9611 val = xmlXPathVariableLookup(ctxt->context, op->value4);
9612 if (val == NULL) {
9613 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
9614 return(0);
9615 }
9616 valuePush(ctxt, val);
9617 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009618 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009619
Daniel Veillardf06307e2001-07-03 10:35:50 +00009620 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9621 if (URI == NULL) {
9622 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009623 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009624 op->value4, op->value5);
9625 return (total);
9626 }
Daniel Veillard556c6682001-10-06 09:59:51 +00009627 val = xmlXPathVariableLookupNS(ctxt->context,
9628 op->value4, URI);
9629 if (val == NULL) {
9630 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
9631 return(0);
9632 }
9633 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009634 }
9635 return (total);
9636 }
9637 case XPATH_OP_FUNCTION:{
9638 xmlXPathFunction func;
9639 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +00009640 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009641
9642 if (op->ch1 != -1)
9643 total +=
9644 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009645 if (ctxt->valueNr < op->value) {
9646 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009647 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +00009648 ctxt->error = XPATH_INVALID_OPERAND;
9649 return (total);
9650 }
9651 for (i = 0; i < op->value; i++)
9652 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
9653 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009654 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +00009655 ctxt->error = XPATH_INVALID_OPERAND;
9656 return (total);
9657 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009658 if (op->cache != NULL)
9659 func = (xmlXPathFunction) op->cache;
9660 else {
9661 const xmlChar *URI = NULL;
9662
9663 if (op->value5 == NULL)
9664 func =
9665 xmlXPathFunctionLookup(ctxt->context,
9666 op->value4);
9667 else {
9668 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9669 if (URI == NULL) {
9670 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009671 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009672 op->value4, op->value5);
9673 return (total);
9674 }
9675 func = xmlXPathFunctionLookupNS(ctxt->context,
9676 op->value4, URI);
9677 }
9678 if (func == NULL) {
9679 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009680 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009681 op->value4);
9682 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009683 }
9684 op->cache = (void *) func;
9685 op->cacheURI = (void *) URI;
9686 }
9687 oldFunc = ctxt->context->function;
9688 oldFuncURI = ctxt->context->functionURI;
9689 ctxt->context->function = op->value4;
9690 ctxt->context->functionURI = op->cacheURI;
9691 func(ctxt, op->value);
9692 ctxt->context->function = oldFunc;
9693 ctxt->context->functionURI = oldFuncURI;
9694 return (total);
9695 }
9696 case XPATH_OP_ARG:
9697 if (op->ch1 != -1)
9698 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009699 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009700 if (op->ch2 != -1)
9701 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009702 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009703 return (total);
9704 case XPATH_OP_PREDICATE:
9705 case XPATH_OP_FILTER:{
9706 xmlXPathObjectPtr res;
9707 xmlXPathObjectPtr obj, tmp;
9708 xmlNodeSetPtr newset = NULL;
9709 xmlNodeSetPtr oldset;
9710 xmlNodePtr oldnode;
9711 int i;
9712
9713 /*
9714 * Optimization for ()[1] selection i.e. the first elem
9715 */
9716 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9717 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9718 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
9719 xmlXPathObjectPtr val;
9720
9721 val = comp->steps[op->ch2].value4;
9722 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
9723 (val->floatval == 1.0)) {
9724 xmlNodePtr first = NULL;
9725
9726 total +=
9727 xmlXPathCompOpEvalFirst(ctxt,
9728 &comp->steps[op->ch1],
9729 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009730 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009731 /*
9732 * The nodeset should be in document order,
9733 * Keep only the first value
9734 */
9735 if ((ctxt->value != NULL) &&
9736 (ctxt->value->type == XPATH_NODESET) &&
9737 (ctxt->value->nodesetval != NULL) &&
9738 (ctxt->value->nodesetval->nodeNr > 1))
9739 ctxt->value->nodesetval->nodeNr = 1;
9740 return (total);
9741 }
9742 }
9743 /*
9744 * Optimization for ()[last()] selection i.e. the last elem
9745 */
9746 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9747 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9748 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
9749 int f = comp->steps[op->ch2].ch1;
9750
9751 if ((f != -1) &&
9752 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
9753 (comp->steps[f].value5 == NULL) &&
9754 (comp->steps[f].value == 0) &&
9755 (comp->steps[f].value4 != NULL) &&
9756 (xmlStrEqual
9757 (comp->steps[f].value4, BAD_CAST "last"))) {
9758 xmlNodePtr last = NULL;
9759
9760 total +=
9761 xmlXPathCompOpEvalLast(ctxt,
9762 &comp->steps[op->ch1],
9763 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009764 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009765 /*
9766 * The nodeset should be in document order,
9767 * Keep only the last value
9768 */
9769 if ((ctxt->value != NULL) &&
9770 (ctxt->value->type == XPATH_NODESET) &&
9771 (ctxt->value->nodesetval != NULL) &&
9772 (ctxt->value->nodesetval->nodeTab != NULL) &&
9773 (ctxt->value->nodesetval->nodeNr > 1)) {
9774 ctxt->value->nodesetval->nodeTab[0] =
9775 ctxt->value->nodesetval->nodeTab[ctxt->
9776 value->
9777 nodesetval->
9778 nodeNr -
9779 1];
9780 ctxt->value->nodesetval->nodeNr = 1;
9781 }
9782 return (total);
9783 }
9784 }
9785
9786 if (op->ch1 != -1)
9787 total +=
9788 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009789 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009790 if (op->ch2 == -1)
9791 return (total);
9792 if (ctxt->value == NULL)
9793 return (total);
9794
9795 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009796
9797#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00009798 /*
9799 * Hum are we filtering the result of an XPointer expression
9800 */
9801 if (ctxt->value->type == XPATH_LOCATIONSET) {
9802 xmlLocationSetPtr newlocset = NULL;
9803 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009804
Daniel Veillardf06307e2001-07-03 10:35:50 +00009805 /*
9806 * Extract the old locset, and then evaluate the result of the
9807 * expression for all the element in the locset. use it to grow
9808 * up a new locset.
9809 */
9810 CHECK_TYPE0(XPATH_LOCATIONSET);
9811 obj = valuePop(ctxt);
9812 oldlocset = obj->user;
9813 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009814
Daniel Veillardf06307e2001-07-03 10:35:50 +00009815 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
9816 ctxt->context->contextSize = 0;
9817 ctxt->context->proximityPosition = 0;
9818 if (op->ch2 != -1)
9819 total +=
9820 xmlXPathCompOpEval(ctxt,
9821 &comp->steps[op->ch2]);
9822 res = valuePop(ctxt);
9823 if (res != NULL)
9824 xmlXPathFreeObject(res);
9825 valuePush(ctxt, obj);
9826 CHECK_ERROR0;
9827 return (total);
9828 }
9829 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009830
Daniel Veillardf06307e2001-07-03 10:35:50 +00009831 for (i = 0; i < oldlocset->locNr; i++) {
9832 /*
9833 * Run the evaluation with a node list made of a
9834 * single item in the nodelocset.
9835 */
9836 ctxt->context->node = oldlocset->locTab[i]->user;
9837 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9838 valuePush(ctxt, tmp);
9839 ctxt->context->contextSize = oldlocset->locNr;
9840 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009841
Daniel Veillardf06307e2001-07-03 10:35:50 +00009842 if (op->ch2 != -1)
9843 total +=
9844 xmlXPathCompOpEval(ctxt,
9845 &comp->steps[op->ch2]);
9846 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009847
Daniel Veillardf06307e2001-07-03 10:35:50 +00009848 /*
9849 * The result of the evaluation need to be tested to
9850 * decided whether the filter succeeded or not
9851 */
9852 res = valuePop(ctxt);
9853 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
9854 xmlXPtrLocationSetAdd(newlocset,
9855 xmlXPathObjectCopy
9856 (oldlocset->locTab[i]));
9857 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009858
Daniel Veillardf06307e2001-07-03 10:35:50 +00009859 /*
9860 * Cleanup
9861 */
9862 if (res != NULL)
9863 xmlXPathFreeObject(res);
9864 if (ctxt->value == tmp) {
9865 res = valuePop(ctxt);
9866 xmlXPathFreeObject(res);
9867 }
9868
9869 ctxt->context->node = NULL;
9870 }
9871
9872 /*
9873 * The result is used as the new evaluation locset.
9874 */
9875 xmlXPathFreeObject(obj);
9876 ctxt->context->node = NULL;
9877 ctxt->context->contextSize = -1;
9878 ctxt->context->proximityPosition = -1;
9879 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
9880 ctxt->context->node = oldnode;
9881 return (total);
9882 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009883#endif /* LIBXML_XPTR_ENABLED */
9884
Daniel Veillardf06307e2001-07-03 10:35:50 +00009885 /*
9886 * Extract the old set, and then evaluate the result of the
9887 * expression for all the element in the set. use it to grow
9888 * up a new set.
9889 */
9890 CHECK_TYPE0(XPATH_NODESET);
9891 obj = valuePop(ctxt);
9892 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00009893
Daniel Veillardf06307e2001-07-03 10:35:50 +00009894 oldnode = ctxt->context->node;
9895 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009896
Daniel Veillardf06307e2001-07-03 10:35:50 +00009897 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
9898 ctxt->context->contextSize = 0;
9899 ctxt->context->proximityPosition = 0;
9900 if (op->ch2 != -1)
9901 total +=
9902 xmlXPathCompOpEval(ctxt,
9903 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009904 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009905 res = valuePop(ctxt);
9906 if (res != NULL)
9907 xmlXPathFreeObject(res);
9908 valuePush(ctxt, obj);
9909 ctxt->context->node = oldnode;
9910 CHECK_ERROR0;
9911 } else {
9912 /*
9913 * Initialize the new set.
9914 */
9915 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009916
Daniel Veillardf06307e2001-07-03 10:35:50 +00009917 for (i = 0; i < oldset->nodeNr; i++) {
9918 /*
9919 * Run the evaluation with a node list made of
9920 * a single item in the nodeset.
9921 */
9922 ctxt->context->node = oldset->nodeTab[i];
9923 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9924 valuePush(ctxt, tmp);
9925 ctxt->context->contextSize = oldset->nodeNr;
9926 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009927
Daniel Veillardf06307e2001-07-03 10:35:50 +00009928 if (op->ch2 != -1)
9929 total +=
9930 xmlXPathCompOpEval(ctxt,
9931 &comp->steps[op->ch2]);
9932 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009933
Daniel Veillardf06307e2001-07-03 10:35:50 +00009934 /*
9935 * The result of the evaluation need to be tested to
9936 * decided whether the filter succeeded or not
9937 */
9938 res = valuePop(ctxt);
9939 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
9940 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
9941 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009942
Daniel Veillardf06307e2001-07-03 10:35:50 +00009943 /*
9944 * Cleanup
9945 */
9946 if (res != NULL)
9947 xmlXPathFreeObject(res);
9948 if (ctxt->value == tmp) {
9949 res = valuePop(ctxt);
9950 xmlXPathFreeObject(res);
9951 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009952
Daniel Veillardf06307e2001-07-03 10:35:50 +00009953 ctxt->context->node = NULL;
9954 }
9955
9956 /*
9957 * The result is used as the new evaluation set.
9958 */
9959 xmlXPathFreeObject(obj);
9960 ctxt->context->node = NULL;
9961 ctxt->context->contextSize = -1;
9962 ctxt->context->proximityPosition = -1;
9963 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
9964 }
9965 ctxt->context->node = oldnode;
9966 return (total);
9967 }
9968 case XPATH_OP_SORT:
9969 if (op->ch1 != -1)
9970 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009971 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009972 if ((ctxt->value != NULL) &&
9973 (ctxt->value->type == XPATH_NODESET) &&
9974 (ctxt->value->nodesetval != NULL))
9975 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9976 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009977#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00009978 case XPATH_OP_RANGETO:{
9979 xmlXPathObjectPtr range;
9980 xmlXPathObjectPtr res, obj;
9981 xmlXPathObjectPtr tmp;
9982 xmlLocationSetPtr newset = NULL;
9983 xmlNodeSetPtr oldset;
9984 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009985
Daniel Veillardf06307e2001-07-03 10:35:50 +00009986 if (op->ch1 != -1)
9987 total +=
9988 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9989 if (op->ch2 == -1)
9990 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009991
Daniel Veillardf06307e2001-07-03 10:35:50 +00009992 CHECK_TYPE0(XPATH_NODESET);
9993 obj = valuePop(ctxt);
9994 oldset = obj->nodesetval;
9995 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009996
Daniel Veillardf06307e2001-07-03 10:35:50 +00009997 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009998
Daniel Veillardf06307e2001-07-03 10:35:50 +00009999 if (oldset != NULL) {
10000 for (i = 0; i < oldset->nodeNr; i++) {
10001 /*
10002 * Run the evaluation with a node list made of a single item
10003 * in the nodeset.
10004 */
10005 ctxt->context->node = oldset->nodeTab[i];
10006 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10007 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010008
Daniel Veillardf06307e2001-07-03 10:35:50 +000010009 if (op->ch2 != -1)
10010 total +=
10011 xmlXPathCompOpEval(ctxt,
10012 &comp->steps[op->ch2]);
10013 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010014
Daniel Veillardf06307e2001-07-03 10:35:50 +000010015 /*
10016 * The result of the evaluation need to be tested to
10017 * decided whether the filter succeeded or not
10018 */
10019 res = valuePop(ctxt);
10020 range =
10021 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10022 res);
10023 if (range != NULL) {
10024 xmlXPtrLocationSetAdd(newset, range);
10025 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010026
Daniel Veillardf06307e2001-07-03 10:35:50 +000010027 /*
10028 * Cleanup
10029 */
10030 if (res != NULL)
10031 xmlXPathFreeObject(res);
10032 if (ctxt->value == tmp) {
10033 res = valuePop(ctxt);
10034 xmlXPathFreeObject(res);
10035 }
10036
10037 ctxt->context->node = NULL;
10038 }
10039 }
10040
10041 /*
10042 * The result is used as the new evaluation set.
10043 */
10044 xmlXPathFreeObject(obj);
10045 ctxt->context->node = NULL;
10046 ctxt->context->contextSize = -1;
10047 ctxt->context->proximityPosition = -1;
10048 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
10049 return (total);
10050 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010051#endif /* LIBXML_XPTR_ENABLED */
10052 }
10053 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010054 "XPath: unknown precompiled operation %d\n", op->op);
10055 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010056}
10057
10058/**
10059 * xmlXPathRunEval:
10060 * @ctxt: the XPath parser context with the compiled expression
10061 *
10062 * Evaluate the Precompiled XPath expression in the given context.
10063 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010064static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010065xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10066 xmlXPathCompExprPtr comp;
10067
10068 if ((ctxt == NULL) || (ctxt->comp == NULL))
10069 return;
10070
10071 if (ctxt->valueTab == NULL) {
10072 /* Allocate the value stack */
10073 ctxt->valueTab = (xmlXPathObjectPtr *)
10074 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10075 if (ctxt->valueTab == NULL) {
10076 xmlFree(ctxt);
10077 xmlGenericError(xmlGenericErrorContext,
10078 "xmlXPathRunEval: out of memory\n");
10079 return;
10080 }
10081 ctxt->valueNr = 0;
10082 ctxt->valueMax = 10;
10083 ctxt->value = NULL;
10084 }
10085 comp = ctxt->comp;
10086 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10087}
10088
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010089/************************************************************************
10090 * *
10091 * Public interfaces *
10092 * *
10093 ************************************************************************/
10094
10095/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010096 * xmlXPathEvalPredicate:
10097 * @ctxt: the XPath context
10098 * @res: the Predicate Expression evaluation result
10099 *
10100 * Evaluate a predicate result for the current node.
10101 * A PredicateExpr is evaluated by evaluating the Expr and converting
10102 * the result to a boolean. If the result is a number, the result will
10103 * be converted to true if the number is equal to the position of the
10104 * context node in the context node list (as returned by the position
10105 * function) and will be converted to false otherwise; if the result
10106 * is not a number, then the result will be converted as if by a call
10107 * to the boolean function.
10108 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010109 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010110 */
10111int
10112xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
10113 if (res == NULL) return(0);
10114 switch (res->type) {
10115 case XPATH_BOOLEAN:
10116 return(res->boolval);
10117 case XPATH_NUMBER:
10118 return(res->floatval == ctxt->proximityPosition);
10119 case XPATH_NODESET:
10120 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010121 if (res->nodesetval == NULL)
10122 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010123 return(res->nodesetval->nodeNr != 0);
10124 case XPATH_STRING:
10125 return((res->stringval != NULL) &&
10126 (xmlStrlen(res->stringval) != 0));
10127 default:
10128 STRANGE
10129 }
10130 return(0);
10131}
10132
10133/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010134 * xmlXPathEvaluatePredicateResult:
10135 * @ctxt: the XPath Parser context
10136 * @res: the Predicate Expression evaluation result
10137 *
10138 * Evaluate a predicate result for the current node.
10139 * A PredicateExpr is evaluated by evaluating the Expr and converting
10140 * the result to a boolean. If the result is a number, the result will
10141 * be converted to true if the number is equal to the position of the
10142 * context node in the context node list (as returned by the position
10143 * function) and will be converted to false otherwise; if the result
10144 * is not a number, then the result will be converted as if by a call
10145 * to the boolean function.
10146 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010147 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010148 */
10149int
10150xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10151 xmlXPathObjectPtr res) {
10152 if (res == NULL) return(0);
10153 switch (res->type) {
10154 case XPATH_BOOLEAN:
10155 return(res->boolval);
10156 case XPATH_NUMBER:
10157 return(res->floatval == ctxt->context->proximityPosition);
10158 case XPATH_NODESET:
10159 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000010160 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000010161 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010162 return(res->nodesetval->nodeNr != 0);
10163 case XPATH_STRING:
10164 return((res->stringval != NULL) &&
10165 (xmlStrlen(res->stringval) != 0));
10166 default:
10167 STRANGE
10168 }
10169 return(0);
10170}
10171
10172/**
10173 * xmlXPathCompile:
10174 * @str: the XPath expression
10175 *
10176 * Compile an XPath expression
10177 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010178 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010179 * the caller has to free the object.
10180 */
10181xmlXPathCompExprPtr
10182xmlXPathCompile(const xmlChar *str) {
10183 xmlXPathParserContextPtr ctxt;
10184 xmlXPathCompExprPtr comp;
10185
10186 xmlXPathInit();
10187
10188 ctxt = xmlXPathNewParserContext(str, NULL);
10189 xmlXPathCompileExpr(ctxt);
10190
Daniel Veillard40af6492001-04-22 08:50:55 +000010191 if (*ctxt->cur != 0) {
10192 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10193 comp = NULL;
10194 } else {
10195 comp = ctxt->comp;
10196 ctxt->comp = NULL;
10197 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010198 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010199#ifdef DEBUG_EVAL_COUNTS
10200 if (comp != NULL) {
10201 comp->string = xmlStrdup(str);
10202 comp->nb = 0;
10203 }
10204#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010205 return(comp);
10206}
10207
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010208/**
10209 * xmlXPathCompiledEval:
10210 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000010211 * @ctx: the XPath context
10212 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010213 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000010214 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010215 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000010216 * the caller has to free the object.
10217 */
10218xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010219xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000010220 xmlXPathParserContextPtr ctxt;
10221 xmlXPathObjectPtr res, tmp, init = NULL;
10222 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000010223#ifndef LIBXML_THREAD_ENABLED
10224 static int reentance = 0;
10225#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010226
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010227 if ((comp == NULL) || (ctx == NULL))
10228 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010229 xmlXPathInit();
10230
10231 CHECK_CONTEXT(ctx)
10232
Daniel Veillard81463942001-10-16 12:34:39 +000010233#ifndef LIBXML_THREAD_ENABLED
10234 reentance++;
10235 if (reentance > 1)
10236 xmlXPathDisableOptimizer = 1;
10237#endif
10238
Daniel Veillardf06307e2001-07-03 10:35:50 +000010239#ifdef DEBUG_EVAL_COUNTS
10240 comp->nb++;
10241 if ((comp->string != NULL) && (comp->nb > 100)) {
10242 fprintf(stderr, "100 x %s\n", comp->string);
10243 comp->nb = 0;
10244 }
10245#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010246 ctxt = xmlXPathCompParserContext(comp, ctx);
10247 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010248
10249 if (ctxt->value == NULL) {
10250 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010251 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000010252 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000010253 } else {
10254 res = valuePop(ctxt);
10255 }
10256
Daniel Veillardf06307e2001-07-03 10:35:50 +000010257
Owen Taylor3473f882001-02-23 17:55:21 +000010258 do {
10259 tmp = valuePop(ctxt);
10260 if (tmp != NULL) {
10261 if (tmp != init)
10262 stack++;
10263 xmlXPathFreeObject(tmp);
10264 }
10265 } while (tmp != NULL);
10266 if ((stack != 0) && (res != NULL)) {
10267 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010268 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000010269 stack);
10270 }
10271 if (ctxt->error != XPATH_EXPRESSION_OK) {
10272 xmlXPathFreeObject(res);
10273 res = NULL;
10274 }
10275
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010276
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010277 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010278 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000010279#ifndef LIBXML_THREAD_ENABLED
10280 reentance--;
10281#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010282 return(res);
10283}
10284
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010285/**
10286 * xmlXPathEvalExpr:
10287 * @ctxt: the XPath Parser context
10288 *
10289 * Parse and evaluate an XPath expression in the given context,
10290 * then push the result on the context stack
10291 */
10292void
10293xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
10294 xmlXPathCompileExpr(ctxt);
10295 xmlXPathRunEval(ctxt);
10296}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010297
10298/**
10299 * xmlXPathEval:
10300 * @str: the XPath expression
10301 * @ctx: the XPath context
10302 *
10303 * Evaluate the XPath Location Path in the given context.
10304 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010305 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010306 * the caller has to free the object.
10307 */
10308xmlXPathObjectPtr
10309xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
10310 xmlXPathParserContextPtr ctxt;
10311 xmlXPathObjectPtr res, tmp, init = NULL;
10312 int stack = 0;
10313
10314 xmlXPathInit();
10315
10316 CHECK_CONTEXT(ctx)
10317
10318 ctxt = xmlXPathNewParserContext(str, ctx);
10319 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010320
10321 if (ctxt->value == NULL) {
10322 xmlGenericError(xmlGenericErrorContext,
10323 "xmlXPathEval: evaluation failed\n");
10324 res = NULL;
10325 } else if (*ctxt->cur != 0) {
10326 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10327 res = NULL;
10328 } else {
10329 res = valuePop(ctxt);
10330 }
10331
10332 do {
10333 tmp = valuePop(ctxt);
10334 if (tmp != NULL) {
10335 if (tmp != init)
10336 stack++;
10337 xmlXPathFreeObject(tmp);
10338 }
10339 } while (tmp != NULL);
10340 if ((stack != 0) && (res != NULL)) {
10341 xmlGenericError(xmlGenericErrorContext,
10342 "xmlXPathEval: %d object left on the stack\n",
10343 stack);
10344 }
10345 if (ctxt->error != XPATH_EXPRESSION_OK) {
10346 xmlXPathFreeObject(res);
10347 res = NULL;
10348 }
10349
Owen Taylor3473f882001-02-23 17:55:21 +000010350 xmlXPathFreeParserContext(ctxt);
10351 return(res);
10352}
10353
10354/**
10355 * xmlXPathEvalExpression:
10356 * @str: the XPath expression
10357 * @ctxt: the XPath context
10358 *
10359 * Evaluate the XPath expression in the given context.
10360 *
10361 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
10362 * the caller has to free the object.
10363 */
10364xmlXPathObjectPtr
10365xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
10366 xmlXPathParserContextPtr pctxt;
10367 xmlXPathObjectPtr res, tmp;
10368 int stack = 0;
10369
10370 xmlXPathInit();
10371
10372 CHECK_CONTEXT(ctxt)
10373
10374 pctxt = xmlXPathNewParserContext(str, ctxt);
10375 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010376
10377 if (*pctxt->cur != 0) {
10378 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10379 res = NULL;
10380 } else {
10381 res = valuePop(pctxt);
10382 }
10383 do {
10384 tmp = valuePop(pctxt);
10385 if (tmp != NULL) {
10386 xmlXPathFreeObject(tmp);
10387 stack++;
10388 }
10389 } while (tmp != NULL);
10390 if ((stack != 0) && (res != NULL)) {
10391 xmlGenericError(xmlGenericErrorContext,
10392 "xmlXPathEvalExpression: %d object left on the stack\n",
10393 stack);
10394 }
10395 xmlXPathFreeParserContext(pctxt);
10396 return(res);
10397}
10398
10399/**
10400 * xmlXPathRegisterAllFunctions:
10401 * @ctxt: the XPath context
10402 *
10403 * Registers all default XPath functions in this context
10404 */
10405void
10406xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
10407{
10408 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
10409 xmlXPathBooleanFunction);
10410 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
10411 xmlXPathCeilingFunction);
10412 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
10413 xmlXPathCountFunction);
10414 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
10415 xmlXPathConcatFunction);
10416 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
10417 xmlXPathContainsFunction);
10418 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
10419 xmlXPathIdFunction);
10420 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
10421 xmlXPathFalseFunction);
10422 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
10423 xmlXPathFloorFunction);
10424 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
10425 xmlXPathLastFunction);
10426 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
10427 xmlXPathLangFunction);
10428 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
10429 xmlXPathLocalNameFunction);
10430 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
10431 xmlXPathNotFunction);
10432 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
10433 xmlXPathNameFunction);
10434 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
10435 xmlXPathNamespaceURIFunction);
10436 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
10437 xmlXPathNormalizeFunction);
10438 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
10439 xmlXPathNumberFunction);
10440 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
10441 xmlXPathPositionFunction);
10442 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
10443 xmlXPathRoundFunction);
10444 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
10445 xmlXPathStringFunction);
10446 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
10447 xmlXPathStringLengthFunction);
10448 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
10449 xmlXPathStartsWithFunction);
10450 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
10451 xmlXPathSubstringFunction);
10452 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
10453 xmlXPathSubstringBeforeFunction);
10454 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
10455 xmlXPathSubstringAfterFunction);
10456 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
10457 xmlXPathSumFunction);
10458 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
10459 xmlXPathTrueFunction);
10460 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
10461 xmlXPathTranslateFunction);
10462}
10463
10464#endif /* LIBXML_XPATH_ENABLED */