blob: e3f89ceca5d828f83e26374113df28ccd44a8cfd [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * xpath.c: XML Path Language implementation
3 * XPath is a language for addressing parts of an XML document,
4 * designed to be used by both XSLT and XPointer
5 *
6 * Reference: W3C Recommendation 16 November 1999
7 * http://www.w3.org/TR/1999/REC-xpath-19991116
8 * Public reference:
9 * http://www.w3.org/TR/xpath
10 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011 * See Copyright for the status of this software
Owen Taylor3473f882001-02-23 17:55:21 +000012 *
Daniel Veillardc5d64342001-06-24 12:13:24 +000013 * Author: daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000014 *
15 * 14 Nov 2000 ht - truncated declaration of xmlXPathEvalRelativeLocationPath
16 * for VMS
17 */
18
Daniel Veillard34ce8be2002-03-18 19:37:11 +000019#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000020#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000021#ifdef LIBXML_XPATH_ENABLED
22
Owen Taylor3473f882001-02-23 17:55:21 +000023#include <string.h>
24
25#ifdef HAVE_SYS_TYPES_H
26#include <sys/types.h>
27#endif
28#ifdef HAVE_MATH_H
29#include <math.h>
30#endif
31#ifdef HAVE_FLOAT_H
32#include <float.h>
33#endif
Owen Taylor3473f882001-02-23 17:55:21 +000034#ifdef HAVE_CTYPE_H
35#include <ctype.h>
36#endif
Daniel Veillard5792e162001-04-30 17:44:45 +000037#ifdef HAVE_SIGNAL_H
Daniel Veillardb45c43b2001-04-28 17:02:11 +000038#include <signal.h>
Daniel Veillardb45c43b2001-04-28 17:02:11 +000039#endif
Owen Taylor3473f882001-02-23 17:55:21 +000040
41#include <libxml/xmlmemory.h>
42#include <libxml/tree.h>
43#include <libxml/valid.h>
44#include <libxml/xpath.h>
45#include <libxml/xpathInternals.h>
46#include <libxml/parserInternals.h>
47#include <libxml/hash.h>
48#ifdef LIBXML_XPTR_ENABLED
49#include <libxml/xpointer.h>
50#endif
51#ifdef LIBXML_DEBUG_ENABLED
52#include <libxml/debugXML.h>
53#endif
54#include <libxml/xmlerror.h>
Daniel Veillard81463942001-10-16 12:34:39 +000055#include <libxml/threads.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000056#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000057
58/* #define DEBUG */
59/* #define DEBUG_STEP */
Daniel Veillardf06307e2001-07-03 10:35:50 +000060/* #define DEBUG_STEP_NTH */
Owen Taylor3473f882001-02-23 17:55:21 +000061/* #define DEBUG_EXPR */
Daniel Veillardf06307e2001-07-03 10:35:50 +000062/* #define DEBUG_EVAL_COUNTS */
Owen Taylor3473f882001-02-23 17:55:21 +000063
Daniel Veillard5792e162001-04-30 17:44:45 +000064double xmlXPathDivideBy(double f, double fzero);
Owen Taylor3473f882001-02-23 17:55:21 +000065
Daniel Veillard20ee8c02001-10-05 09:18:14 +000066static xmlNs xmlXPathXMLNamespaceStruct = {
67 NULL,
68 XML_NAMESPACE_DECL,
69 XML_XML_NAMESPACE,
70 BAD_CAST "xml"
71};
72static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
Daniel Veillard81463942001-10-16 12:34:39 +000073#ifndef LIBXML_THREADS_ENABLED
74/*
75 * Optimizer is disabled only when threaded apps are detected while
76 * the library ain't compiled for thread safety.
77 */
78static int xmlXPathDisableOptimizer = 0;
79#endif
Daniel Veillard20ee8c02001-10-05 09:18:14 +000080
Daniel Veillard9e7160d2001-03-18 23:17:47 +000081/************************************************************************
82 * *
83 * Floating point stuff *
84 * *
85 ************************************************************************/
86
Daniel Veillardc0631a62001-09-20 13:56:06 +000087#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +000088#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +000089#endif
Daniel Veillardcda96922001-08-21 10:56:31 +000090#include "trionan.c"
91
Owen Taylor3473f882001-02-23 17:55:21 +000092/*
Owen Taylor3473f882001-02-23 17:55:21 +000093 * The lack of portability of this section of the libc is annoying !
94 */
95double xmlXPathNAN = 0;
96double xmlXPathPINF = 1;
97double xmlXPathNINF = -1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +000098double xmlXPathNZERO = 0;
Daniel Veillard20ee8c02001-10-05 09:18:14 +000099static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000100
Owen Taylor3473f882001-02-23 17:55:21 +0000101/**
102 * xmlXPathInit:
103 *
104 * Initialize the XPath environment
105 */
106void
107xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000108 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +0000109
Bjorn Reese45029602001-08-21 09:23:53 +0000110 xmlXPathPINF = trio_pinf();
111 xmlXPathNINF = trio_ninf();
112 xmlXPathNAN = trio_nan();
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000113 xmlXPathNZERO = trio_nzero();
Owen Taylor3473f882001-02-23 17:55:21 +0000114
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000115 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000116}
117
Daniel Veillardcda96922001-08-21 10:56:31 +0000118/**
119 * xmlXPathIsNaN:
120 * @val: a double value
121 *
122 * Provides a portable isnan() function to detect whether a double
123 * is a NotaNumber. Based on trio code
124 * http://sourceforge.net/projects/ctrio/
125 *
126 * Returns 1 if the value is a NaN, 0 otherwise
127 */
128int
129xmlXPathIsNaN(double val) {
130 return(trio_isnan(val));
131}
132
133/**
134 * xmlXPathIsInf:
135 * @val: a double value
136 *
137 * Provides a portable isinf() function to detect whether a double
138 * is a +Infinite or -Infinite. Based on trio code
139 * http://sourceforge.net/projects/ctrio/
140 *
141 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
142 */
143int
144xmlXPathIsInf(double val) {
145 return(trio_isinf(val));
146}
147
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000148/**
149 * xmlXPathGetSign:
150 * @val: a double value
151 *
152 * Provides a portable function to detect the sign of a double
153 * Modified from trio code
154 * http://sourceforge.net/projects/ctrio/
155 *
156 * Returns 1 if the value is Negative, 0 if positive
157 */
Daniel Veillard21458c82002-03-27 16:12:22 +0000158static int
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000159xmlXPathGetSign(double val) {
Daniel Veillard21458c82002-03-27 16:12:22 +0000160 return(trio_signbit(val));
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000161}
162
163
Owen Taylor3473f882001-02-23 17:55:21 +0000164/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000165 * *
166 * Parser Types *
167 * *
168 ************************************************************************/
169
170/*
171 * Types are private:
172 */
173
174typedef enum {
175 XPATH_OP_END=0,
176 XPATH_OP_AND,
177 XPATH_OP_OR,
178 XPATH_OP_EQUAL,
179 XPATH_OP_CMP,
180 XPATH_OP_PLUS,
181 XPATH_OP_MULT,
182 XPATH_OP_UNION,
183 XPATH_OP_ROOT,
184 XPATH_OP_NODE,
185 XPATH_OP_RESET,
186 XPATH_OP_COLLECT,
187 XPATH_OP_VALUE,
188 XPATH_OP_VARIABLE,
189 XPATH_OP_FUNCTION,
190 XPATH_OP_ARG,
191 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000192 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000193 XPATH_OP_SORT
194#ifdef LIBXML_XPTR_ENABLED
195 ,XPATH_OP_RANGETO
196#endif
197} xmlXPathOp;
198
199typedef enum {
200 AXIS_ANCESTOR = 1,
201 AXIS_ANCESTOR_OR_SELF,
202 AXIS_ATTRIBUTE,
203 AXIS_CHILD,
204 AXIS_DESCENDANT,
205 AXIS_DESCENDANT_OR_SELF,
206 AXIS_FOLLOWING,
207 AXIS_FOLLOWING_SIBLING,
208 AXIS_NAMESPACE,
209 AXIS_PARENT,
210 AXIS_PRECEDING,
211 AXIS_PRECEDING_SIBLING,
212 AXIS_SELF
213} xmlXPathAxisVal;
214
215typedef enum {
216 NODE_TEST_NONE = 0,
217 NODE_TEST_TYPE = 1,
218 NODE_TEST_PI = 2,
219 NODE_TEST_ALL = 3,
220 NODE_TEST_NS = 4,
221 NODE_TEST_NAME = 5
222} xmlXPathTestVal;
223
224typedef enum {
225 NODE_TYPE_NODE = 0,
226 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
227 NODE_TYPE_TEXT = XML_TEXT_NODE,
228 NODE_TYPE_PI = XML_PI_NODE
229} xmlXPathTypeVal;
230
231
232typedef struct _xmlXPathStepOp xmlXPathStepOp;
233typedef xmlXPathStepOp *xmlXPathStepOpPtr;
234struct _xmlXPathStepOp {
235 xmlXPathOp op;
236 int ch1;
237 int ch2;
238 int value;
239 int value2;
240 int value3;
241 void *value4;
242 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000243 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000244 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000245};
246
247struct _xmlXPathCompExpr {
248 int nbStep;
249 int maxStep;
250 xmlXPathStepOp *steps; /* ops for computation */
251 int last;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000252#ifdef DEBUG_EVAL_COUNTS
253 int nb;
254 xmlChar *string;
255#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000256};
257
258/************************************************************************
259 * *
260 * Parser Type functions *
261 * *
262 ************************************************************************/
263
264/**
265 * xmlXPathNewCompExpr:
266 *
267 * Create a new Xpath component
268 *
269 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
270 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000271static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000272xmlXPathNewCompExpr(void) {
273 xmlXPathCompExprPtr cur;
274
275 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
276 if (cur == NULL) {
277 xmlGenericError(xmlGenericErrorContext,
278 "xmlXPathNewCompExpr : malloc failed\n");
279 return(NULL);
280 }
281 memset(cur, 0, sizeof(xmlXPathCompExpr));
282 cur->maxStep = 10;
283 cur->nbStep = 0;
284 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
285 sizeof(xmlXPathStepOp));
286 if (cur->steps == NULL) {
287 xmlGenericError(xmlGenericErrorContext,
288 "xmlXPathNewCompExpr : malloc failed\n");
289 xmlFree(cur);
290 return(NULL);
291 }
292 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
293 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000294#ifdef DEBUG_EVAL_COUNTS
295 cur->nb = 0;
296#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000297 return(cur);
298}
299
300/**
301 * xmlXPathFreeCompExpr:
302 * @comp: an XPATH comp
303 *
304 * Free up the memory allocated by @comp
305 */
306void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000307xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
308{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000309 xmlXPathStepOpPtr op;
310 int i;
311
312 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000313 return;
314 for (i = 0; i < comp->nbStep; i++) {
315 op = &comp->steps[i];
316 if (op->value4 != NULL) {
317 if (op->op == XPATH_OP_VALUE)
318 xmlXPathFreeObject(op->value4);
319 else
320 xmlFree(op->value4);
321 }
322 if (op->value5 != NULL)
323 xmlFree(op->value5);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000324 }
325 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000326 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000327 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000328#ifdef DEBUG_EVAL_COUNTS
329 if (comp->string != NULL) {
330 xmlFree(comp->string);
331 }
332#endif
333
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000334 xmlFree(comp);
335}
336
337/**
338 * xmlXPathCompExprAdd:
339 * @comp: the compiled expression
340 * @ch1: first child index
341 * @ch2: second child index
342 * @op: an op
343 * @value: the first int value
344 * @value2: the second int value
345 * @value3: the third int value
346 * @value4: the first string value
347 * @value5: the second string value
348 *
349 * Add an step to an XPath Compiled Expression
350 *
351 * Returns -1 in case of failure, the index otherwise
352 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000353static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000354xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
355 xmlXPathOp op, int value,
356 int value2, int value3, void *value4, void *value5) {
357 if (comp->nbStep >= comp->maxStep) {
358 xmlXPathStepOp *real;
359
360 comp->maxStep *= 2;
361 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
362 comp->maxStep * sizeof(xmlXPathStepOp));
363 if (real == NULL) {
364 comp->maxStep /= 2;
365 xmlGenericError(xmlGenericErrorContext,
366 "xmlXPathCompExprAdd : realloc failed\n");
367 return(-1);
368 }
369 comp->steps = real;
370 }
371 comp->last = comp->nbStep;
372 comp->steps[comp->nbStep].ch1 = ch1;
373 comp->steps[comp->nbStep].ch2 = ch2;
374 comp->steps[comp->nbStep].op = op;
375 comp->steps[comp->nbStep].value = value;
376 comp->steps[comp->nbStep].value2 = value2;
377 comp->steps[comp->nbStep].value3 = value3;
378 comp->steps[comp->nbStep].value4 = value4;
379 comp->steps[comp->nbStep].value5 = value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000380 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000381 return(comp->nbStep++);
382}
383
Daniel Veillardf06307e2001-07-03 10:35:50 +0000384/**
385 * xmlXPathCompSwap:
386 * @comp: the compiled expression
387 * @op: operation index
388 *
389 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000390 */
391static void
392xmlXPathCompSwap(xmlXPathStepOpPtr op) {
393 int tmp;
394
Daniel Veillard81463942001-10-16 12:34:39 +0000395#ifdef LIBXML_THREADS_ENABLED
396 /*
397 * Since this manipulates possibly shared variables, this is
398 * disable if one detects that the library is used in a multithreaded
399 * application
400 */
401 if (xmlXPathDisableOptimizer)
402 return;
403#endif
404
Daniel Veillardf06307e2001-07-03 10:35:50 +0000405 tmp = op->ch1;
406 op->ch1 = op->ch2;
407 op->ch2 = tmp;
408}
409
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000410#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
411 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
412 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000413#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
414 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
415 (op), (val), (val2), (val3), (val4), (val5))
416
417#define PUSH_LEAVE_EXPR(op, val, val2) \
418xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
419
420#define PUSH_UNARY_EXPR(op, ch, val, val2) \
421xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
422
423#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
424xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), (val), (val2), 0 ,NULL ,NULL)
425
426/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000427 * *
428 * Debugging related functions *
429 * *
430 ************************************************************************/
431
432#define TODO \
433 xmlGenericError(xmlGenericErrorContext, \
434 "Unimplemented block at %s:%d\n", \
435 __FILE__, __LINE__);
436
437#define STRANGE \
438 xmlGenericError(xmlGenericErrorContext, \
439 "Internal error at %s:%d\n", \
440 __FILE__, __LINE__);
441
442#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000443static void
444xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000445 int i;
446 char shift[100];
447
448 for (i = 0;((i < depth) && (i < 25));i++)
449 shift[2 * i] = shift[2 * i + 1] = ' ';
450 shift[2 * i] = shift[2 * i + 1] = 0;
451 if (cur == NULL) {
452 fprintf(output, shift);
453 fprintf(output, "Node is NULL !\n");
454 return;
455
456 }
457
458 if ((cur->type == XML_DOCUMENT_NODE) ||
459 (cur->type == XML_HTML_DOCUMENT_NODE)) {
460 fprintf(output, shift);
461 fprintf(output, " /\n");
462 } else if (cur->type == XML_ATTRIBUTE_NODE)
463 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
464 else
465 xmlDebugDumpOneNode(output, cur, depth);
466}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000467static void
468xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000469 xmlNodePtr tmp;
470 int i;
471 char shift[100];
472
473 for (i = 0;((i < depth) && (i < 25));i++)
474 shift[2 * i] = shift[2 * i + 1] = ' ';
475 shift[2 * i] = shift[2 * i + 1] = 0;
476 if (cur == NULL) {
477 fprintf(output, shift);
478 fprintf(output, "Node is NULL !\n");
479 return;
480
481 }
482
483 while (cur != NULL) {
484 tmp = cur;
485 cur = cur->next;
486 xmlDebugDumpOneNode(output, tmp, depth);
487 }
488}
Owen Taylor3473f882001-02-23 17:55:21 +0000489
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000490static void
491xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000492 int i;
493 char shift[100];
494
495 for (i = 0;((i < depth) && (i < 25));i++)
496 shift[2 * i] = shift[2 * i + 1] = ' ';
497 shift[2 * i] = shift[2 * i + 1] = 0;
498
499 if (cur == NULL) {
500 fprintf(output, shift);
501 fprintf(output, "NodeSet is NULL !\n");
502 return;
503
504 }
505
Daniel Veillard911f49a2001-04-07 15:39:35 +0000506 if (cur != NULL) {
507 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
508 for (i = 0;i < cur->nodeNr;i++) {
509 fprintf(output, shift);
510 fprintf(output, "%d", i + 1);
511 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
512 }
Owen Taylor3473f882001-02-23 17:55:21 +0000513 }
514}
515
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000516static void
517xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000518 int i;
519 char shift[100];
520
521 for (i = 0;((i < depth) && (i < 25));i++)
522 shift[2 * i] = shift[2 * i + 1] = ' ';
523 shift[2 * i] = shift[2 * i + 1] = 0;
524
525 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
526 fprintf(output, shift);
527 fprintf(output, "Value Tree is NULL !\n");
528 return;
529
530 }
531
532 fprintf(output, shift);
533 fprintf(output, "%d", i + 1);
534 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
535}
Owen Taylor3473f882001-02-23 17:55:21 +0000536#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000537static void
538xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000539 int i;
540 char shift[100];
541
542 for (i = 0;((i < depth) && (i < 25));i++)
543 shift[2 * i] = shift[2 * i + 1] = ' ';
544 shift[2 * i] = shift[2 * i + 1] = 0;
545
546 if (cur == NULL) {
547 fprintf(output, shift);
548 fprintf(output, "LocationSet is NULL !\n");
549 return;
550
551 }
552
553 for (i = 0;i < cur->locNr;i++) {
554 fprintf(output, shift);
555 fprintf(output, "%d : ", i + 1);
556 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
557 }
558}
Daniel Veillard017b1082001-06-21 11:20:21 +0000559#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000560
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000561/**
562 * xmlXPathDebugDumpObject:
563 * @output: the FILE * to dump the output
564 * @cur: the object to inspect
565 * @depth: indentation level
566 *
567 * Dump the content of the object for debugging purposes
568 */
569void
570xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000571 int i;
572 char shift[100];
573
574 for (i = 0;((i < depth) && (i < 25));i++)
575 shift[2 * i] = shift[2 * i + 1] = ' ';
576 shift[2 * i] = shift[2 * i + 1] = 0;
577
578 fprintf(output, shift);
579
580 if (cur == NULL) {
581 fprintf(output, "Object is empty (NULL)\n");
582 return;
583 }
584 switch(cur->type) {
585 case XPATH_UNDEFINED:
586 fprintf(output, "Object is uninitialized\n");
587 break;
588 case XPATH_NODESET:
589 fprintf(output, "Object is a Node Set :\n");
590 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
591 break;
592 case XPATH_XSLT_TREE:
593 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000594 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000595 break;
596 case XPATH_BOOLEAN:
597 fprintf(output, "Object is a Boolean : ");
598 if (cur->boolval) fprintf(output, "true\n");
599 else fprintf(output, "false\n");
600 break;
601 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +0000602 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000603 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000604 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000605 break;
606 case -1:
607 fprintf(output, "Object is a number : -Infinity\n");
608 break;
609 default:
Daniel Veillardcda96922001-08-21 10:56:31 +0000610 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000611 fprintf(output, "Object is a number : NaN\n");
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
Daniel Veillard21458c82002-03-27 16:12:22 +00001278xmlXPatherror(xmlXPathParserContextPtr ctxt, ATTRIBUTE_UNUSED const char *file,
1279 ATTRIBUTE_UNUSED int line, int no) {
Owen Taylor3473f882001-02-23 17:55:21 +00001280 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:
Daniel Veillard21458c82002-03-27 16:12:22 +00004475 /* Hand checking NaNs for VC6++'s benefit... */
4476 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4477 ret = 0;
4478 } else {
4479 ret = (arg1->floatval == arg2->floatval);
4480 }
Owen Taylor3473f882001-02-23 17:55:21 +00004481 break;
4482 case XPATH_USERS:
4483 case XPATH_POINT:
4484 case XPATH_RANGE:
4485 case XPATH_LOCATIONSET:
4486 TODO
4487 break;
4488 }
4489 break;
4490 case XPATH_STRING:
4491 switch (arg2->type) {
4492 case XPATH_UNDEFINED:
4493#ifdef DEBUG_EXPR
4494 xmlGenericError(xmlGenericErrorContext,
4495 "Equal: undefined\n");
4496#endif
4497 break;
4498 case XPATH_NODESET:
4499 case XPATH_XSLT_TREE:
4500 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
4501 break;
4502 case XPATH_BOOLEAN:
4503 if ((arg1->stringval == NULL) ||
4504 (arg1->stringval[0] == 0)) ret = 0;
4505 else
4506 ret = 1;
4507 ret = (arg2->boolval == ret);
4508 break;
4509 case XPATH_STRING:
4510 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4511 break;
4512 case XPATH_NUMBER:
4513 valuePush(ctxt, arg1);
4514 xmlXPathNumberFunction(ctxt, 1);
4515 arg1 = valuePop(ctxt);
Daniel Veillard21458c82002-03-27 16:12:22 +00004516 /* Hand checking NaNs for VC6++'s benefit... */
4517 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4518 ret = 0;
4519 } else {
4520 ret = (arg1->floatval == arg2->floatval);
4521 }
Owen Taylor3473f882001-02-23 17:55:21 +00004522 break;
4523 case XPATH_USERS:
4524 case XPATH_POINT:
4525 case XPATH_RANGE:
4526 case XPATH_LOCATIONSET:
4527 TODO
4528 break;
4529 }
4530 break;
4531 case XPATH_USERS:
4532 case XPATH_POINT:
4533 case XPATH_RANGE:
4534 case XPATH_LOCATIONSET:
4535 TODO
4536 break;
4537 }
4538 xmlXPathFreeObject(arg1);
4539 xmlXPathFreeObject(arg2);
4540 return(ret);
4541}
4542
4543
4544/**
4545 * xmlXPathCompareValues:
4546 * @ctxt: the XPath Parser context
4547 * @inf: less than (1) or greater than (0)
4548 * @strict: is the comparison strict
4549 *
4550 * Implement the compare operation on XPath objects:
4551 * @arg1 < @arg2 (1, 1, ...
4552 * @arg1 <= @arg2 (1, 0, ...
4553 * @arg1 > @arg2 (0, 1, ...
4554 * @arg1 >= @arg2 (0, 0, ...
4555 *
4556 * When neither object to be compared is a node-set and the operator is
4557 * <=, <, >=, >, then the objects are compared by converted both objects
4558 * to numbers and comparing the numbers according to IEEE 754. The <
4559 * comparison will be true if and only if the first number is less than the
4560 * second number. The <= comparison will be true if and only if the first
4561 * number is less than or equal to the second number. The > comparison
4562 * will be true if and only if the first number is greater than the second
4563 * number. The >= comparison will be true if and only if the first number
4564 * is greater than or equal to the second number.
4565 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004566 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00004567 */
4568int
4569xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
4570 int ret = 0;
4571 xmlXPathObjectPtr arg1, arg2;
4572
4573 arg2 = valuePop(ctxt);
4574 if (arg2 == NULL) {
4575 XP_ERROR0(XPATH_INVALID_OPERAND);
4576 }
4577
4578 arg1 = valuePop(ctxt);
4579 if (arg1 == NULL) {
4580 xmlXPathFreeObject(arg2);
4581 XP_ERROR0(XPATH_INVALID_OPERAND);
4582 }
4583
4584 if ((arg2->type == XPATH_NODESET) || (arg1->type == XPATH_NODESET)) {
4585 if ((arg2->type == XPATH_NODESET) && (arg1->type == XPATH_NODESET)) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004586 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004587 } else {
4588 if (arg1->type == XPATH_NODESET) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004589 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
4590 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004591 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004592 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
4593 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00004594 }
4595 }
4596 return(ret);
4597 }
4598
4599 if (arg1->type != XPATH_NUMBER) {
4600 valuePush(ctxt, arg1);
4601 xmlXPathNumberFunction(ctxt, 1);
4602 arg1 = valuePop(ctxt);
4603 }
4604 if (arg1->type != XPATH_NUMBER) {
4605 xmlXPathFreeObject(arg1);
4606 xmlXPathFreeObject(arg2);
4607 XP_ERROR0(XPATH_INVALID_OPERAND);
4608 }
4609 if (arg2->type != XPATH_NUMBER) {
4610 valuePush(ctxt, arg2);
4611 xmlXPathNumberFunction(ctxt, 1);
4612 arg2 = valuePop(ctxt);
4613 }
4614 if (arg2->type != XPATH_NUMBER) {
4615 xmlXPathFreeObject(arg1);
4616 xmlXPathFreeObject(arg2);
4617 XP_ERROR0(XPATH_INVALID_OPERAND);
4618 }
4619 /*
4620 * Add tests for infinity and nan
4621 * => feedback on 3.4 for Inf and NaN
4622 */
Daniel Veillard21458c82002-03-27 16:12:22 +00004623 /* Hand checking NaNs for VC++6's benefit... */
4624 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4625 ret=0;
4626 } else {
4627 if (inf && strict)
4628 ret = (arg1->floatval < arg2->floatval);
4629 else if (inf && !strict)
4630 ret = (arg1->floatval <= arg2->floatval);
4631 else if (!inf && strict)
4632 ret = (arg1->floatval > arg2->floatval);
4633 else if (!inf && !strict)
4634 ret = (arg1->floatval >= arg2->floatval);
4635 }
Owen Taylor3473f882001-02-23 17:55:21 +00004636 xmlXPathFreeObject(arg1);
4637 xmlXPathFreeObject(arg2);
4638 return(ret);
4639}
4640
4641/**
4642 * xmlXPathValueFlipSign:
4643 * @ctxt: the XPath Parser context
4644 *
4645 * Implement the unary - operation on an XPath object
4646 * The numeric operators convert their operands to numbers as if
4647 * by calling the number function.
4648 */
4649void
4650xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004651 CAST_TO_NUMBER;
4652 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00004653 if (ctxt->value->floatval == 0) {
4654 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
4655 ctxt->value->floatval = xmlXPathNZERO;
4656 else
4657 ctxt->value->floatval = 0;
4658 }
4659 else
4660 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00004661}
4662
4663/**
4664 * xmlXPathAddValues:
4665 * @ctxt: the XPath Parser context
4666 *
4667 * Implement the add operation on XPath objects:
4668 * The numeric operators convert their operands to numbers as if
4669 * by calling the number function.
4670 */
4671void
4672xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
4673 xmlXPathObjectPtr arg;
4674 double val;
4675
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004676 arg = valuePop(ctxt);
4677 if (arg == NULL)
4678 XP_ERROR(XPATH_INVALID_OPERAND);
4679 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004680 xmlXPathFreeObject(arg);
4681
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004682 CAST_TO_NUMBER;
4683 CHECK_TYPE(XPATH_NUMBER);
4684 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00004685}
4686
4687/**
4688 * xmlXPathSubValues:
4689 * @ctxt: the XPath Parser context
4690 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004691 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00004692 * The numeric operators convert their operands to numbers as if
4693 * by calling the number function.
4694 */
4695void
4696xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
4697 xmlXPathObjectPtr arg;
4698 double val;
4699
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004700 arg = valuePop(ctxt);
4701 if (arg == NULL)
4702 XP_ERROR(XPATH_INVALID_OPERAND);
4703 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004704 xmlXPathFreeObject(arg);
4705
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004706 CAST_TO_NUMBER;
4707 CHECK_TYPE(XPATH_NUMBER);
4708 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004709}
4710
4711/**
4712 * xmlXPathMultValues:
4713 * @ctxt: the XPath Parser context
4714 *
4715 * Implement the multiply operation on XPath objects:
4716 * The numeric operators convert their operands to numbers as if
4717 * by calling the number function.
4718 */
4719void
4720xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
4721 xmlXPathObjectPtr arg;
4722 double val;
4723
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004724 arg = valuePop(ctxt);
4725 if (arg == NULL)
4726 XP_ERROR(XPATH_INVALID_OPERAND);
4727 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004728 xmlXPathFreeObject(arg);
4729
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004730 CAST_TO_NUMBER;
4731 CHECK_TYPE(XPATH_NUMBER);
4732 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004733}
4734
4735/**
4736 * xmlXPathDivValues:
4737 * @ctxt: the XPath Parser context
4738 *
4739 * Implement the div operation on XPath objects @arg1 / @arg2:
4740 * The numeric operators convert their operands to numbers as if
4741 * by calling the number function.
4742 */
4743void
4744xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
4745 xmlXPathObjectPtr arg;
4746 double val;
4747
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004748 arg = valuePop(ctxt);
4749 if (arg == NULL)
4750 XP_ERROR(XPATH_INVALID_OPERAND);
4751 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004752 xmlXPathFreeObject(arg);
4753
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004754 CAST_TO_NUMBER;
4755 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00004756 if (val == 0 && xmlXPathGetSign(val) == 1) {
4757 if (ctxt->value->floatval == 0)
4758 ctxt->value->floatval = xmlXPathNAN;
4759 else if (ctxt->value->floatval > 0)
4760 ctxt->value->floatval = xmlXPathNINF;
4761 else if (ctxt->value->floatval < 0)
4762 ctxt->value->floatval = xmlXPathPINF;
4763 }
4764 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00004765 if (ctxt->value->floatval == 0)
4766 ctxt->value->floatval = xmlXPathNAN;
4767 else if (ctxt->value->floatval > 0)
4768 ctxt->value->floatval = xmlXPathPINF;
4769 else if (ctxt->value->floatval < 0)
4770 ctxt->value->floatval = xmlXPathNINF;
4771 } else
4772 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004773}
4774
4775/**
4776 * xmlXPathModValues:
4777 * @ctxt: the XPath Parser context
4778 *
4779 * Implement the mod operation on XPath objects: @arg1 / @arg2
4780 * The numeric operators convert their operands to numbers as if
4781 * by calling the number function.
4782 */
4783void
4784xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
4785 xmlXPathObjectPtr arg;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00004786 double arg1, arg2, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00004787
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004788 arg = valuePop(ctxt);
4789 if (arg == NULL)
4790 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00004791 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004792 xmlXPathFreeObject(arg);
4793
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004794 CAST_TO_NUMBER;
4795 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00004796 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00004797 if (arg2 == 0)
4798 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00004799 else {
4800 tmp=arg1/arg2;
4801 ctxt->value->floatval = arg2 * (tmp - (double)((int)tmp));
4802 }
Owen Taylor3473f882001-02-23 17:55:21 +00004803}
4804
4805/************************************************************************
4806 * *
4807 * The traversal functions *
4808 * *
4809 ************************************************************************/
4810
Owen Taylor3473f882001-02-23 17:55:21 +00004811/*
4812 * A traversal function enumerates nodes along an axis.
4813 * Initially it must be called with NULL, and it indicates
4814 * termination on the axis by returning NULL.
4815 */
4816typedef xmlNodePtr (*xmlXPathTraversalFunction)
4817 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
4818
4819/**
4820 * xmlXPathNextSelf:
4821 * @ctxt: the XPath Parser context
4822 * @cur: the current node in the traversal
4823 *
4824 * Traversal function for the "self" direction
4825 * The self axis contains just the context node itself
4826 *
4827 * Returns the next element following that axis
4828 */
4829xmlNodePtr
4830xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4831 if (cur == NULL)
4832 return(ctxt->context->node);
4833 return(NULL);
4834}
4835
4836/**
4837 * xmlXPathNextChild:
4838 * @ctxt: the XPath Parser context
4839 * @cur: the current node in the traversal
4840 *
4841 * Traversal function for the "child" direction
4842 * The child axis contains the children of the context node in document order.
4843 *
4844 * Returns the next element following that axis
4845 */
4846xmlNodePtr
4847xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4848 if (cur == NULL) {
4849 if (ctxt->context->node == NULL) return(NULL);
4850 switch (ctxt->context->node->type) {
4851 case XML_ELEMENT_NODE:
4852 case XML_TEXT_NODE:
4853 case XML_CDATA_SECTION_NODE:
4854 case XML_ENTITY_REF_NODE:
4855 case XML_ENTITY_NODE:
4856 case XML_PI_NODE:
4857 case XML_COMMENT_NODE:
4858 case XML_NOTATION_NODE:
4859 case XML_DTD_NODE:
4860 return(ctxt->context->node->children);
4861 case XML_DOCUMENT_NODE:
4862 case XML_DOCUMENT_TYPE_NODE:
4863 case XML_DOCUMENT_FRAG_NODE:
4864 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004865#ifdef LIBXML_DOCB_ENABLED
4866 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004867#endif
4868 return(((xmlDocPtr) ctxt->context->node)->children);
4869 case XML_ELEMENT_DECL:
4870 case XML_ATTRIBUTE_DECL:
4871 case XML_ENTITY_DECL:
4872 case XML_ATTRIBUTE_NODE:
4873 case XML_NAMESPACE_DECL:
4874 case XML_XINCLUDE_START:
4875 case XML_XINCLUDE_END:
4876 return(NULL);
4877 }
4878 return(NULL);
4879 }
4880 if ((cur->type == XML_DOCUMENT_NODE) ||
4881 (cur->type == XML_HTML_DOCUMENT_NODE))
4882 return(NULL);
4883 return(cur->next);
4884}
4885
4886/**
4887 * xmlXPathNextDescendant:
4888 * @ctxt: the XPath Parser context
4889 * @cur: the current node in the traversal
4890 *
4891 * Traversal function for the "descendant" direction
4892 * the descendant axis contains the descendants of the context node in document
4893 * order; a descendant is a child or a child of a child and so on.
4894 *
4895 * Returns the next element following that axis
4896 */
4897xmlNodePtr
4898xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4899 if (cur == NULL) {
4900 if (ctxt->context->node == NULL)
4901 return(NULL);
4902 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4903 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4904 return(NULL);
4905
4906 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
4907 return(ctxt->context->doc->children);
4908 return(ctxt->context->node->children);
4909 }
4910
Daniel Veillard567e1b42001-08-01 15:53:47 +00004911 if (cur->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004912 if (cur->children->type != XML_ENTITY_DECL)
Daniel Veillard567e1b42001-08-01 15:53:47 +00004913 return(cur->children);
4914 }
4915
4916 if (cur == ctxt->context->node) return(NULL);
4917
Owen Taylor3473f882001-02-23 17:55:21 +00004918 if (cur->next != NULL) return(cur->next);
4919
4920 do {
4921 cur = cur->parent;
4922 if (cur == NULL) return(NULL);
4923 if (cur == ctxt->context->node) return(NULL);
4924 if (cur->next != NULL) {
4925 cur = cur->next;
4926 return(cur);
4927 }
4928 } while (cur != NULL);
4929 return(cur);
4930}
4931
4932/**
4933 * xmlXPathNextDescendantOrSelf:
4934 * @ctxt: the XPath Parser context
4935 * @cur: the current node in the traversal
4936 *
4937 * Traversal function for the "descendant-or-self" direction
4938 * the descendant-or-self axis contains the context node and the descendants
4939 * of the context node in document order; thus the context node is the first
4940 * node on the axis, and the first child of the context node is the second node
4941 * on the axis
4942 *
4943 * Returns the next element following that axis
4944 */
4945xmlNodePtr
4946xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4947 if (cur == NULL) {
4948 if (ctxt->context->node == NULL)
4949 return(NULL);
4950 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4951 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4952 return(NULL);
4953 return(ctxt->context->node);
4954 }
4955
4956 return(xmlXPathNextDescendant(ctxt, cur));
4957}
4958
4959/**
4960 * xmlXPathNextParent:
4961 * @ctxt: the XPath Parser context
4962 * @cur: the current node in the traversal
4963 *
4964 * Traversal function for the "parent" direction
4965 * The parent axis contains the parent of the context node, if there is one.
4966 *
4967 * Returns the next element following that axis
4968 */
4969xmlNodePtr
4970xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4971 /*
4972 * the parent of an attribute or namespace node is the element
4973 * to which the attribute or namespace node is attached
4974 * Namespace handling !!!
4975 */
4976 if (cur == NULL) {
4977 if (ctxt->context->node == NULL) return(NULL);
4978 switch (ctxt->context->node->type) {
4979 case XML_ELEMENT_NODE:
4980 case XML_TEXT_NODE:
4981 case XML_CDATA_SECTION_NODE:
4982 case XML_ENTITY_REF_NODE:
4983 case XML_ENTITY_NODE:
4984 case XML_PI_NODE:
4985 case XML_COMMENT_NODE:
4986 case XML_NOTATION_NODE:
4987 case XML_DTD_NODE:
4988 case XML_ELEMENT_DECL:
4989 case XML_ATTRIBUTE_DECL:
4990 case XML_XINCLUDE_START:
4991 case XML_XINCLUDE_END:
4992 case XML_ENTITY_DECL:
4993 if (ctxt->context->node->parent == NULL)
4994 return((xmlNodePtr) ctxt->context->doc);
4995 return(ctxt->context->node->parent);
4996 case XML_ATTRIBUTE_NODE: {
4997 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
4998
4999 return(att->parent);
5000 }
5001 case XML_DOCUMENT_NODE:
5002 case XML_DOCUMENT_TYPE_NODE:
5003 case XML_DOCUMENT_FRAG_NODE:
5004 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005005#ifdef LIBXML_DOCB_ENABLED
5006 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005007#endif
5008 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005009 case XML_NAMESPACE_DECL: {
5010 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5011
5012 if ((ns->next != NULL) &&
5013 (ns->next->type != XML_NAMESPACE_DECL))
5014 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005015 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005016 }
Owen Taylor3473f882001-02-23 17:55:21 +00005017 }
5018 }
5019 return(NULL);
5020}
5021
5022/**
5023 * xmlXPathNextAncestor:
5024 * @ctxt: the XPath Parser context
5025 * @cur: the current node in the traversal
5026 *
5027 * Traversal function for the "ancestor" direction
5028 * the ancestor axis contains the ancestors of the context node; the ancestors
5029 * of the context node consist of the parent of context node and the parent's
5030 * parent and so on; the nodes are ordered in reverse document order; thus the
5031 * parent is the first node on the axis, and the parent's parent is the second
5032 * node on the axis
5033 *
5034 * Returns the next element following that axis
5035 */
5036xmlNodePtr
5037xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5038 /*
5039 * the parent of an attribute or namespace node is the element
5040 * to which the attribute or namespace node is attached
5041 * !!!!!!!!!!!!!
5042 */
5043 if (cur == NULL) {
5044 if (ctxt->context->node == NULL) return(NULL);
5045 switch (ctxt->context->node->type) {
5046 case XML_ELEMENT_NODE:
5047 case XML_TEXT_NODE:
5048 case XML_CDATA_SECTION_NODE:
5049 case XML_ENTITY_REF_NODE:
5050 case XML_ENTITY_NODE:
5051 case XML_PI_NODE:
5052 case XML_COMMENT_NODE:
5053 case XML_DTD_NODE:
5054 case XML_ELEMENT_DECL:
5055 case XML_ATTRIBUTE_DECL:
5056 case XML_ENTITY_DECL:
5057 case XML_NOTATION_NODE:
5058 case XML_XINCLUDE_START:
5059 case XML_XINCLUDE_END:
5060 if (ctxt->context->node->parent == NULL)
5061 return((xmlNodePtr) ctxt->context->doc);
5062 return(ctxt->context->node->parent);
5063 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005064 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005065
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005066 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005067 }
5068 case XML_DOCUMENT_NODE:
5069 case XML_DOCUMENT_TYPE_NODE:
5070 case XML_DOCUMENT_FRAG_NODE:
5071 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005072#ifdef LIBXML_DOCB_ENABLED
5073 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005074#endif
5075 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005076 case XML_NAMESPACE_DECL: {
5077 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5078
5079 if ((ns->next != NULL) &&
5080 (ns->next->type != XML_NAMESPACE_DECL))
5081 return((xmlNodePtr) ns->next);
5082 /* Bad, how did that namespace ended-up there ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005083 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005084 }
Owen Taylor3473f882001-02-23 17:55:21 +00005085 }
5086 return(NULL);
5087 }
5088 if (cur == ctxt->context->doc->children)
5089 return((xmlNodePtr) ctxt->context->doc);
5090 if (cur == (xmlNodePtr) ctxt->context->doc)
5091 return(NULL);
5092 switch (cur->type) {
5093 case XML_ELEMENT_NODE:
5094 case XML_TEXT_NODE:
5095 case XML_CDATA_SECTION_NODE:
5096 case XML_ENTITY_REF_NODE:
5097 case XML_ENTITY_NODE:
5098 case XML_PI_NODE:
5099 case XML_COMMENT_NODE:
5100 case XML_NOTATION_NODE:
5101 case XML_DTD_NODE:
5102 case XML_ELEMENT_DECL:
5103 case XML_ATTRIBUTE_DECL:
5104 case XML_ENTITY_DECL:
5105 case XML_XINCLUDE_START:
5106 case XML_XINCLUDE_END:
5107 return(cur->parent);
5108 case XML_ATTRIBUTE_NODE: {
5109 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5110
5111 return(att->parent);
5112 }
5113 case XML_DOCUMENT_NODE:
5114 case XML_DOCUMENT_TYPE_NODE:
5115 case XML_DOCUMENT_FRAG_NODE:
5116 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005117#ifdef LIBXML_DOCB_ENABLED
5118 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005119#endif
5120 return(NULL);
5121 case XML_NAMESPACE_DECL:
5122 /*
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005123 * this should not hapen a namespace can't be
5124 * the ancestor of another node
Owen Taylor3473f882001-02-23 17:55:21 +00005125 */
5126 return(NULL);
5127 }
5128 return(NULL);
5129}
5130
5131/**
5132 * xmlXPathNextAncestorOrSelf:
5133 * @ctxt: the XPath Parser context
5134 * @cur: the current node in the traversal
5135 *
5136 * Traversal function for the "ancestor-or-self" direction
5137 * he ancestor-or-self axis contains the context node and ancestors of
5138 * the context node in reverse document order; thus the context node is
5139 * the first node on the axis, and the context node's parent the second;
5140 * parent here is defined the same as with the parent axis.
5141 *
5142 * Returns the next element following that axis
5143 */
5144xmlNodePtr
5145xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5146 if (cur == NULL)
5147 return(ctxt->context->node);
5148 return(xmlXPathNextAncestor(ctxt, cur));
5149}
5150
5151/**
5152 * xmlXPathNextFollowingSibling:
5153 * @ctxt: the XPath Parser context
5154 * @cur: the current node in the traversal
5155 *
5156 * Traversal function for the "following-sibling" direction
5157 * The following-sibling axis contains the following siblings of the context
5158 * node in document order.
5159 *
5160 * Returns the next element following that axis
5161 */
5162xmlNodePtr
5163xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5164 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5165 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5166 return(NULL);
5167 if (cur == (xmlNodePtr) ctxt->context->doc)
5168 return(NULL);
5169 if (cur == NULL)
5170 return(ctxt->context->node->next);
5171 return(cur->next);
5172}
5173
5174/**
5175 * xmlXPathNextPrecedingSibling:
5176 * @ctxt: the XPath Parser context
5177 * @cur: the current node in the traversal
5178 *
5179 * Traversal function for the "preceding-sibling" direction
5180 * The preceding-sibling axis contains the preceding siblings of the context
5181 * node in reverse document order; the first preceding sibling is first on the
5182 * axis; the sibling preceding that node is the second on the axis and so on.
5183 *
5184 * Returns the next element following that axis
5185 */
5186xmlNodePtr
5187xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5188 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5189 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5190 return(NULL);
5191 if (cur == (xmlNodePtr) ctxt->context->doc)
5192 return(NULL);
5193 if (cur == NULL)
5194 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005195 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5196 cur = cur->prev;
5197 if (cur == NULL)
5198 return(ctxt->context->node->prev);
5199 }
Owen Taylor3473f882001-02-23 17:55:21 +00005200 return(cur->prev);
5201}
5202
5203/**
5204 * xmlXPathNextFollowing:
5205 * @ctxt: the XPath Parser context
5206 * @cur: the current node in the traversal
5207 *
5208 * Traversal function for the "following" direction
5209 * The following axis contains all nodes in the same document as the context
5210 * node that are after the context node in document order, excluding any
5211 * descendants and excluding attribute nodes and namespace nodes; the nodes
5212 * are ordered in document order
5213 *
5214 * Returns the next element following that axis
5215 */
5216xmlNodePtr
5217xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5218 if (cur != NULL && cur->children != NULL)
5219 return cur->children ;
5220 if (cur == NULL) cur = ctxt->context->node;
5221 if (cur == NULL) return(NULL) ; /* ERROR */
5222 if (cur->next != NULL) return(cur->next) ;
5223 do {
5224 cur = cur->parent;
5225 if (cur == NULL) return(NULL);
5226 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5227 if (cur->next != NULL) return(cur->next);
5228 } while (cur != NULL);
5229 return(cur);
5230}
5231
5232/*
5233 * xmlXPathIsAncestor:
5234 * @ancestor: the ancestor node
5235 * @node: the current node
5236 *
5237 * Check that @ancestor is a @node's ancestor
5238 *
5239 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5240 */
5241static int
5242xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5243 if ((ancestor == NULL) || (node == NULL)) return(0);
5244 /* nodes need to be in the same document */
5245 if (ancestor->doc != node->doc) return(0);
5246 /* avoid searching if ancestor or node is the root node */
5247 if (ancestor == (xmlNodePtr) node->doc) return(1);
5248 if (node == (xmlNodePtr) ancestor->doc) return(0);
5249 while (node->parent != NULL) {
5250 if (node->parent == ancestor)
5251 return(1);
5252 node = node->parent;
5253 }
5254 return(0);
5255}
5256
5257/**
5258 * xmlXPathNextPreceding:
5259 * @ctxt: the XPath Parser context
5260 * @cur: the current node in the traversal
5261 *
5262 * Traversal function for the "preceding" direction
5263 * the preceding axis contains all nodes in the same document as the context
5264 * node that are before the context node in document order, excluding any
5265 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5266 * ordered in reverse document order
5267 *
5268 * Returns the next element following that axis
5269 */
5270xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005271xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5272{
Owen Taylor3473f882001-02-23 17:55:21 +00005273 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005274 cur = ctxt->context->node;
5275 if (cur == NULL)
5276 return (NULL);
5277 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5278 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005279 do {
5280 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005281 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5282 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005283 }
5284
5285 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005286 if (cur == NULL)
5287 return (NULL);
5288 if (cur == ctxt->context->doc->children)
5289 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005290 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005291 return (cur);
5292}
5293
5294/**
5295 * xmlXPathNextPrecedingInternal:
5296 * @ctxt: the XPath Parser context
5297 * @cur: the current node in the traversal
5298 *
5299 * Traversal function for the "preceding" direction
5300 * the preceding axis contains all nodes in the same document as the context
5301 * node that are before the context node in document order, excluding any
5302 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5303 * ordered in reverse document order
5304 * This is a faster implementation but internal only since it requires a
5305 * state kept in the parser context: ctxt->ancestor.
5306 *
5307 * Returns the next element following that axis
5308 */
5309static xmlNodePtr
5310xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5311 xmlNodePtr cur)
5312{
5313 if (cur == NULL) {
5314 cur = ctxt->context->node;
5315 if (cur == NULL)
5316 return (NULL);
5317 ctxt->ancestor = cur->parent;
5318 }
5319 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5320 cur = cur->prev;
5321 while (cur->prev == NULL) {
5322 cur = cur->parent;
5323 if (cur == NULL)
5324 return (NULL);
5325 if (cur == ctxt->context->doc->children)
5326 return (NULL);
5327 if (cur != ctxt->ancestor)
5328 return (cur);
5329 ctxt->ancestor = cur->parent;
5330 }
5331 cur = cur->prev;
5332 while (cur->last != NULL)
5333 cur = cur->last;
5334 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005335}
5336
5337/**
5338 * xmlXPathNextNamespace:
5339 * @ctxt: the XPath Parser context
5340 * @cur: the current attribute in the traversal
5341 *
5342 * Traversal function for the "namespace" direction
5343 * the namespace axis contains the namespace nodes of the context node;
5344 * the order of nodes on this axis is implementation-defined; the axis will
5345 * be empty unless the context node is an element
5346 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005347 * We keep the XML namespace node at the end of the list.
5348 *
Owen Taylor3473f882001-02-23 17:55:21 +00005349 * Returns the next element following that axis
5350 */
5351xmlNodePtr
5352xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005353 xmlNodePtr ret;
5354
Owen Taylor3473f882001-02-23 17:55:21 +00005355 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005356 if (cur == (xmlNodePtr) xmlXPathXMLNamespace)
5357 return(NULL);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005358 if ((cur == NULL) || (ctxt->context->tmpNsList == NULL)) {
5359 if (ctxt->context->tmpNsList != NULL)
5360 xmlFree(ctxt->context->tmpNsList);
5361 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005362 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005363 if (ctxt->context->tmpNsList == NULL) return(NULL);
5364 ctxt->context->tmpNsNr = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005365 }
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005366 ret = (xmlNodePtr)ctxt->context->tmpNsList[ctxt->context->tmpNsNr++];
5367 if (ret == NULL) {
5368 xmlFree(ctxt->context->tmpNsList);
5369 ctxt->context->tmpNsList = NULL;
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005370 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005371 }
5372 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005373}
5374
5375/**
5376 * xmlXPathNextAttribute:
5377 * @ctxt: the XPath Parser context
5378 * @cur: the current attribute in the traversal
5379 *
5380 * Traversal function for the "attribute" direction
5381 * TODO: support DTD inherited default attributes
5382 *
5383 * Returns the next element following that axis
5384 */
5385xmlNodePtr
5386xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005387 if (ctxt->context->node == NULL)
5388 return(NULL);
5389 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5390 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005391 if (cur == NULL) {
5392 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5393 return(NULL);
5394 return((xmlNodePtr)ctxt->context->node->properties);
5395 }
5396 return((xmlNodePtr)cur->next);
5397}
5398
5399/************************************************************************
5400 * *
5401 * NodeTest Functions *
5402 * *
5403 ************************************************************************/
5404
Owen Taylor3473f882001-02-23 17:55:21 +00005405#define IS_FUNCTION 200
5406
Owen Taylor3473f882001-02-23 17:55:21 +00005407
5408/************************************************************************
5409 * *
5410 * Implicit tree core function library *
5411 * *
5412 ************************************************************************/
5413
5414/**
5415 * xmlXPathRoot:
5416 * @ctxt: the XPath Parser context
5417 *
5418 * Initialize the context to the root of the document
5419 */
5420void
5421xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5422 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5423 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5424}
5425
5426/************************************************************************
5427 * *
5428 * The explicit core function library *
5429 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5430 * *
5431 ************************************************************************/
5432
5433
5434/**
5435 * xmlXPathLastFunction:
5436 * @ctxt: the XPath Parser context
5437 * @nargs: the number of arguments
5438 *
5439 * Implement the last() XPath function
5440 * number last()
5441 * The last function returns the number of nodes in the context node list.
5442 */
5443void
5444xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5445 CHECK_ARITY(0);
5446 if (ctxt->context->contextSize >= 0) {
5447 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5448#ifdef DEBUG_EXPR
5449 xmlGenericError(xmlGenericErrorContext,
5450 "last() : %d\n", ctxt->context->contextSize);
5451#endif
5452 } else {
5453 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5454 }
5455}
5456
5457/**
5458 * xmlXPathPositionFunction:
5459 * @ctxt: the XPath Parser context
5460 * @nargs: the number of arguments
5461 *
5462 * Implement the position() XPath function
5463 * number position()
5464 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005465 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00005466 * will be equal to last().
5467 */
5468void
5469xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5470 CHECK_ARITY(0);
5471 if (ctxt->context->proximityPosition >= 0) {
5472 valuePush(ctxt,
5473 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5474#ifdef DEBUG_EXPR
5475 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5476 ctxt->context->proximityPosition);
5477#endif
5478 } else {
5479 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5480 }
5481}
5482
5483/**
5484 * xmlXPathCountFunction:
5485 * @ctxt: the XPath Parser context
5486 * @nargs: the number of arguments
5487 *
5488 * Implement the count() XPath function
5489 * number count(node-set)
5490 */
5491void
5492xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5493 xmlXPathObjectPtr cur;
5494
5495 CHECK_ARITY(1);
5496 if ((ctxt->value == NULL) ||
5497 ((ctxt->value->type != XPATH_NODESET) &&
5498 (ctxt->value->type != XPATH_XSLT_TREE)))
5499 XP_ERROR(XPATH_INVALID_TYPE);
5500 cur = valuePop(ctxt);
5501
Daniel Veillard911f49a2001-04-07 15:39:35 +00005502 if ((cur == NULL) || (cur->nodesetval == NULL))
5503 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00005504 else if (cur->type == XPATH_NODESET) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00005505 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00005506 } else {
5507 if ((cur->nodesetval->nodeNr != 1) ||
5508 (cur->nodesetval->nodeTab == NULL)) {
5509 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5510 } else {
5511 xmlNodePtr tmp;
5512 int i = 0;
5513
5514 tmp = cur->nodesetval->nodeTab[0];
5515 if (tmp != NULL) {
5516 tmp = tmp->children;
5517 while (tmp != NULL) {
5518 tmp = tmp->next;
5519 i++;
5520 }
5521 }
5522 valuePush(ctxt, xmlXPathNewFloat((double) i));
5523 }
5524 }
Owen Taylor3473f882001-02-23 17:55:21 +00005525 xmlXPathFreeObject(cur);
5526}
5527
5528/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005529 * xmlXPathGetElementsByIds:
5530 * @doc: the document
5531 * @ids: a whitespace separated list of IDs
5532 *
5533 * Selects elements by their unique ID.
5534 *
5535 * Returns a node-set of selected elements.
5536 */
5537static xmlNodeSetPtr
5538xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5539 xmlNodeSetPtr ret;
5540 const xmlChar *cur = ids;
5541 xmlChar *ID;
5542 xmlAttrPtr attr;
5543 xmlNodePtr elem = NULL;
5544
5545 ret = xmlXPathNodeSetCreate(NULL);
5546
5547 while (IS_BLANK(*cur)) cur++;
5548 while (*cur != 0) {
5549 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
5550 (*cur == '.') || (*cur == '-') ||
5551 (*cur == '_') || (*cur == ':') ||
5552 (IS_COMBINING(*cur)) ||
5553 (IS_EXTENDER(*cur)))
5554 cur++;
5555
5556 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
5557
5558 ID = xmlStrndup(ids, cur - ids);
5559 attr = xmlGetID(doc, ID);
5560 if (attr != NULL) {
5561 elem = attr->parent;
5562 xmlXPathNodeSetAdd(ret, elem);
5563 }
5564 if (ID != NULL)
5565 xmlFree(ID);
5566
5567 while (IS_BLANK(*cur)) cur++;
5568 ids = cur;
5569 }
5570 return(ret);
5571}
5572
5573/**
Owen Taylor3473f882001-02-23 17:55:21 +00005574 * xmlXPathIdFunction:
5575 * @ctxt: the XPath Parser context
5576 * @nargs: the number of arguments
5577 *
5578 * Implement the id() XPath function
5579 * node-set id(object)
5580 * The id function selects elements by their unique ID
5581 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
5582 * then the result is the union of the result of applying id to the
5583 * string value of each of the nodes in the argument node-set. When the
5584 * argument to id is of any other type, the argument is converted to a
5585 * string as if by a call to the string function; the string is split
5586 * into a whitespace-separated list of tokens (whitespace is any sequence
5587 * of characters matching the production S); the result is a node-set
5588 * containing the elements in the same document as the context node that
5589 * have a unique ID equal to any of the tokens in the list.
5590 */
5591void
5592xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005593 xmlChar *tokens;
5594 xmlNodeSetPtr ret;
5595 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00005596
5597 CHECK_ARITY(1);
5598 obj = valuePop(ctxt);
5599 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
5600 if (obj->type == XPATH_NODESET) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005601 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00005602 int i;
5603
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005604 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005605
Daniel Veillard911f49a2001-04-07 15:39:35 +00005606 if (obj->nodesetval != NULL) {
5607 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005608 tokens =
5609 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
5610 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
5611 ret = xmlXPathNodeSetMerge(ret, ns);
5612 xmlXPathFreeNodeSet(ns);
5613 if (tokens != NULL)
5614 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00005615 }
Owen Taylor3473f882001-02-23 17:55:21 +00005616 }
5617
5618 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005619 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005620 return;
5621 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005622 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00005623
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005624 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
5625 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005626
Owen Taylor3473f882001-02-23 17:55:21 +00005627 xmlXPathFreeObject(obj);
5628 return;
5629}
5630
5631/**
5632 * xmlXPathLocalNameFunction:
5633 * @ctxt: the XPath Parser context
5634 * @nargs: the number of arguments
5635 *
5636 * Implement the local-name() XPath function
5637 * string local-name(node-set?)
5638 * The local-name function returns a string containing the local part
5639 * of the name of the node in the argument node-set that is first in
5640 * document order. If the node-set is empty or the first node has no
5641 * name, an empty string is returned. If the argument is omitted it
5642 * defaults to the context node.
5643 */
5644void
5645xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5646 xmlXPathObjectPtr cur;
5647
5648 if (nargs == 0) {
5649 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5650 nargs = 1;
5651 }
5652
5653 CHECK_ARITY(1);
5654 if ((ctxt->value == NULL) ||
5655 ((ctxt->value->type != XPATH_NODESET) &&
5656 (ctxt->value->type != XPATH_XSLT_TREE)))
5657 XP_ERROR(XPATH_INVALID_TYPE);
5658 cur = valuePop(ctxt);
5659
Daniel Veillard911f49a2001-04-07 15:39:35 +00005660 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005661 valuePush(ctxt, xmlXPathNewCString(""));
5662 } else {
5663 int i = 0; /* Should be first in document order !!!!! */
5664 switch (cur->nodesetval->nodeTab[i]->type) {
5665 case XML_ELEMENT_NODE:
5666 case XML_ATTRIBUTE_NODE:
5667 case XML_PI_NODE:
5668 valuePush(ctxt,
5669 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
5670 break;
5671 case XML_NAMESPACE_DECL:
5672 valuePush(ctxt, xmlXPathNewString(
5673 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
5674 break;
5675 default:
5676 valuePush(ctxt, xmlXPathNewCString(""));
5677 }
5678 }
5679 xmlXPathFreeObject(cur);
5680}
5681
5682/**
5683 * xmlXPathNamespaceURIFunction:
5684 * @ctxt: the XPath Parser context
5685 * @nargs: the number of arguments
5686 *
5687 * Implement the namespace-uri() XPath function
5688 * string namespace-uri(node-set?)
5689 * The namespace-uri function returns a string containing the
5690 * namespace URI of the expanded name of the node in the argument
5691 * node-set that is first in document order. If the node-set is empty,
5692 * the first node has no name, or the expanded name has no namespace
5693 * URI, an empty string is returned. If the argument is omitted it
5694 * defaults to the context node.
5695 */
5696void
5697xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5698 xmlXPathObjectPtr cur;
5699
5700 if (nargs == 0) {
5701 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5702 nargs = 1;
5703 }
5704 CHECK_ARITY(1);
5705 if ((ctxt->value == NULL) ||
5706 ((ctxt->value->type != XPATH_NODESET) &&
5707 (ctxt->value->type != XPATH_XSLT_TREE)))
5708 XP_ERROR(XPATH_INVALID_TYPE);
5709 cur = valuePop(ctxt);
5710
Daniel Veillard911f49a2001-04-07 15:39:35 +00005711 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005712 valuePush(ctxt, xmlXPathNewCString(""));
5713 } else {
5714 int i = 0; /* Should be first in document order !!!!! */
5715 switch (cur->nodesetval->nodeTab[i]->type) {
5716 case XML_ELEMENT_NODE:
5717 case XML_ATTRIBUTE_NODE:
5718 if (cur->nodesetval->nodeTab[i]->ns == NULL)
5719 valuePush(ctxt, xmlXPathNewCString(""));
5720 else
5721 valuePush(ctxt, xmlXPathNewString(
5722 cur->nodesetval->nodeTab[i]->ns->href));
5723 break;
5724 default:
5725 valuePush(ctxt, xmlXPathNewCString(""));
5726 }
5727 }
5728 xmlXPathFreeObject(cur);
5729}
5730
5731/**
5732 * xmlXPathNameFunction:
5733 * @ctxt: the XPath Parser context
5734 * @nargs: the number of arguments
5735 *
5736 * Implement the name() XPath function
5737 * string name(node-set?)
5738 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005739 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00005740 * order. The QName must represent the name with respect to the namespace
5741 * declarations in effect on the node whose name is being represented.
5742 * Typically, this will be the form in which the name occurred in the XML
5743 * source. This need not be the case if there are namespace declarations
5744 * in effect on the node that associate multiple prefixes with the same
5745 * namespace. However, an implementation may include information about
5746 * the original prefix in its representation of nodes; in this case, an
5747 * implementation can ensure that the returned string is always the same
5748 * as the QName used in the XML source. If the argument it omitted it
5749 * defaults to the context node.
5750 * Libxml keep the original prefix so the "real qualified name" used is
5751 * returned.
5752 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005753static void
Daniel Veillard04383752001-07-08 14:27:15 +00005754xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
5755{
Owen Taylor3473f882001-02-23 17:55:21 +00005756 xmlXPathObjectPtr cur;
5757
5758 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00005759 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5760 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00005761 }
5762
5763 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00005764 if ((ctxt->value == NULL) ||
5765 ((ctxt->value->type != XPATH_NODESET) &&
5766 (ctxt->value->type != XPATH_XSLT_TREE)))
5767 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00005768 cur = valuePop(ctxt);
5769
Daniel Veillard911f49a2001-04-07 15:39:35 +00005770 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00005771 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00005772 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00005773 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005774
Daniel Veillard04383752001-07-08 14:27:15 +00005775 switch (cur->nodesetval->nodeTab[i]->type) {
5776 case XML_ELEMENT_NODE:
5777 case XML_ATTRIBUTE_NODE:
5778 if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
5779 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL))
5780 valuePush(ctxt,
5781 xmlXPathNewString(cur->nodesetval->
5782 nodeTab[i]->name));
5783
5784 else {
5785 char name[2000];
5786
5787 snprintf(name, sizeof(name), "%s:%s",
5788 (char *) cur->nodesetval->nodeTab[i]->ns->
5789 prefix,
5790 (char *) cur->nodesetval->nodeTab[i]->name);
5791 name[sizeof(name) - 1] = 0;
5792 valuePush(ctxt, xmlXPathNewCString(name));
5793 }
5794 break;
5795 default:
5796 valuePush(ctxt,
5797 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
5798 xmlXPathLocalNameFunction(ctxt, 1);
5799 }
Owen Taylor3473f882001-02-23 17:55:21 +00005800 }
5801 xmlXPathFreeObject(cur);
5802}
5803
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005804
5805/**
Owen Taylor3473f882001-02-23 17:55:21 +00005806 * xmlXPathStringFunction:
5807 * @ctxt: the XPath Parser context
5808 * @nargs: the number of arguments
5809 *
5810 * Implement the string() XPath function
5811 * string string(object?)
5812 * he string function converts an object to a string as follows:
5813 * - A node-set is converted to a string by returning the value of
5814 * the node in the node-set that is first in document order.
5815 * If the node-set is empty, an empty string is returned.
5816 * - A number is converted to a string as follows
5817 * + NaN is converted to the string NaN
5818 * + positive zero is converted to the string 0
5819 * + negative zero is converted to the string 0
5820 * + positive infinity is converted to the string Infinity
5821 * + negative infinity is converted to the string -Infinity
5822 * + if the number is an integer, the number is represented in
5823 * decimal form as a Number with no decimal point and no leading
5824 * zeros, preceded by a minus sign (-) if the number is negative
5825 * + otherwise, the number is represented in decimal form as a
5826 * Number including a decimal point with at least one digit
5827 * before the decimal point and at least one digit after the
5828 * decimal point, preceded by a minus sign (-) if the number
5829 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005830 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00005831 * before the decimal point; beyond the one required digit
5832 * after the decimal point there must be as many, but only as
5833 * many, more digits as are needed to uniquely distinguish the
5834 * number from all other IEEE 754 numeric values.
5835 * - The boolean false value is converted to the string false.
5836 * The boolean true value is converted to the string true.
5837 *
5838 * If the argument is omitted, it defaults to a node-set with the
5839 * context node as its only member.
5840 */
5841void
5842xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5843 xmlXPathObjectPtr cur;
5844
5845 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005846 valuePush(ctxt,
5847 xmlXPathWrapString(
5848 xmlXPathCastNodeToString(ctxt->context->node)));
5849 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005850 }
5851
5852 CHECK_ARITY(1);
5853 cur = valuePop(ctxt);
5854 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005855 cur = xmlXPathConvertString(cur);
5856 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005857}
5858
5859/**
5860 * xmlXPathStringLengthFunction:
5861 * @ctxt: the XPath Parser context
5862 * @nargs: the number of arguments
5863 *
5864 * Implement the string-length() XPath function
5865 * number string-length(string?)
5866 * The string-length returns the number of characters in the string
5867 * (see [3.6 Strings]). If the argument is omitted, it defaults to
5868 * the context node converted to a string, in other words the value
5869 * of the context node.
5870 */
5871void
5872xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5873 xmlXPathObjectPtr cur;
5874
5875 if (nargs == 0) {
5876 if (ctxt->context->node == NULL) {
5877 valuePush(ctxt, xmlXPathNewFloat(0));
5878 } else {
5879 xmlChar *content;
5880
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005881 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00005882 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00005883 xmlFree(content);
5884 }
5885 return;
5886 }
5887 CHECK_ARITY(1);
5888 CAST_TO_STRING;
5889 CHECK_TYPE(XPATH_STRING);
5890 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00005891 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00005892 xmlXPathFreeObject(cur);
5893}
5894
5895/**
5896 * xmlXPathConcatFunction:
5897 * @ctxt: the XPath Parser context
5898 * @nargs: the number of arguments
5899 *
5900 * Implement the concat() XPath function
5901 * string concat(string, string, string*)
5902 * The concat function returns the concatenation of its arguments.
5903 */
5904void
5905xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5906 xmlXPathObjectPtr cur, newobj;
5907 xmlChar *tmp;
5908
5909 if (nargs < 2) {
5910 CHECK_ARITY(2);
5911 }
5912
5913 CAST_TO_STRING;
5914 cur = valuePop(ctxt);
5915 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
5916 xmlXPathFreeObject(cur);
5917 return;
5918 }
5919 nargs--;
5920
5921 while (nargs > 0) {
5922 CAST_TO_STRING;
5923 newobj = valuePop(ctxt);
5924 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
5925 xmlXPathFreeObject(newobj);
5926 xmlXPathFreeObject(cur);
5927 XP_ERROR(XPATH_INVALID_TYPE);
5928 }
5929 tmp = xmlStrcat(newobj->stringval, cur->stringval);
5930 newobj->stringval = cur->stringval;
5931 cur->stringval = tmp;
5932
5933 xmlXPathFreeObject(newobj);
5934 nargs--;
5935 }
5936 valuePush(ctxt, cur);
5937}
5938
5939/**
5940 * xmlXPathContainsFunction:
5941 * @ctxt: the XPath Parser context
5942 * @nargs: the number of arguments
5943 *
5944 * Implement the contains() XPath function
5945 * boolean contains(string, string)
5946 * The contains function returns true if the first argument string
5947 * contains the second argument string, and otherwise returns false.
5948 */
5949void
5950xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5951 xmlXPathObjectPtr hay, needle;
5952
5953 CHECK_ARITY(2);
5954 CAST_TO_STRING;
5955 CHECK_TYPE(XPATH_STRING);
5956 needle = valuePop(ctxt);
5957 CAST_TO_STRING;
5958 hay = valuePop(ctxt);
5959 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
5960 xmlXPathFreeObject(hay);
5961 xmlXPathFreeObject(needle);
5962 XP_ERROR(XPATH_INVALID_TYPE);
5963 }
5964 if (xmlStrstr(hay->stringval, needle->stringval))
5965 valuePush(ctxt, xmlXPathNewBoolean(1));
5966 else
5967 valuePush(ctxt, xmlXPathNewBoolean(0));
5968 xmlXPathFreeObject(hay);
5969 xmlXPathFreeObject(needle);
5970}
5971
5972/**
5973 * xmlXPathStartsWithFunction:
5974 * @ctxt: the XPath Parser context
5975 * @nargs: the number of arguments
5976 *
5977 * Implement the starts-with() XPath function
5978 * boolean starts-with(string, string)
5979 * The starts-with function returns true if the first argument string
5980 * starts with the second argument string, and otherwise returns false.
5981 */
5982void
5983xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5984 xmlXPathObjectPtr hay, needle;
5985 int n;
5986
5987 CHECK_ARITY(2);
5988 CAST_TO_STRING;
5989 CHECK_TYPE(XPATH_STRING);
5990 needle = valuePop(ctxt);
5991 CAST_TO_STRING;
5992 hay = valuePop(ctxt);
5993 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
5994 xmlXPathFreeObject(hay);
5995 xmlXPathFreeObject(needle);
5996 XP_ERROR(XPATH_INVALID_TYPE);
5997 }
5998 n = xmlStrlen(needle->stringval);
5999 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6000 valuePush(ctxt, xmlXPathNewBoolean(0));
6001 else
6002 valuePush(ctxt, xmlXPathNewBoolean(1));
6003 xmlXPathFreeObject(hay);
6004 xmlXPathFreeObject(needle);
6005}
6006
6007/**
6008 * xmlXPathSubstringFunction:
6009 * @ctxt: the XPath Parser context
6010 * @nargs: the number of arguments
6011 *
6012 * Implement the substring() XPath function
6013 * string substring(string, number, number?)
6014 * The substring function returns the substring of the first argument
6015 * starting at the position specified in the second argument with
6016 * length specified in the third argument. For example,
6017 * substring("12345",2,3) returns "234". If the third argument is not
6018 * specified, it returns the substring starting at the position specified
6019 * in the second argument and continuing to the end of the string. For
6020 * example, substring("12345",2) returns "2345". More precisely, each
6021 * character in the string (see [3.6 Strings]) is considered to have a
6022 * numeric position: the position of the first character is 1, the position
6023 * of the second character is 2 and so on. The returned substring contains
6024 * those characters for which the position of the character is greater than
6025 * or equal to the second argument and, if the third argument is specified,
6026 * less than the sum of the second and third arguments; the comparisons
6027 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6028 * - substring("12345", 1.5, 2.6) returns "234"
6029 * - substring("12345", 0, 3) returns "12"
6030 * - substring("12345", 0 div 0, 3) returns ""
6031 * - substring("12345", 1, 0 div 0) returns ""
6032 * - substring("12345", -42, 1 div 0) returns "12345"
6033 * - substring("12345", -1 div 0, 1 div 0) returns ""
6034 */
6035void
6036xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6037 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006038 double le=0, in;
6039 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006040 xmlChar *ret;
6041
Owen Taylor3473f882001-02-23 17:55:21 +00006042 if (nargs < 2) {
6043 CHECK_ARITY(2);
6044 }
6045 if (nargs > 3) {
6046 CHECK_ARITY(3);
6047 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006048 /*
6049 * take care of possible last (position) argument
6050 */
Owen Taylor3473f882001-02-23 17:55:21 +00006051 if (nargs == 3) {
6052 CAST_TO_NUMBER;
6053 CHECK_TYPE(XPATH_NUMBER);
6054 len = valuePop(ctxt);
6055 le = len->floatval;
6056 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006057 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006058
Owen Taylor3473f882001-02-23 17:55:21 +00006059 CAST_TO_NUMBER;
6060 CHECK_TYPE(XPATH_NUMBER);
6061 start = valuePop(ctxt);
6062 in = start->floatval;
6063 xmlXPathFreeObject(start);
6064 CAST_TO_STRING;
6065 CHECK_TYPE(XPATH_STRING);
6066 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006067 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006068
Daniel Veillard97ac1312001-05-30 19:14:17 +00006069 /*
6070 * If last pos not present, calculate last position
6071 */
6072 if (nargs != 3)
6073 le = m;
6074
6075 /*
6076 * To meet our requirements, initial index calculations
6077 * must be done before we convert to integer format
6078 *
6079 * First we normalize indices
6080 */
6081 in -= 1.0;
6082 le += in;
6083 if (in < 0.0)
6084 in = 0.0;
6085 if (le > (double)m)
6086 le = (double)m;
6087
6088 /*
6089 * Now we go to integer form, rounding up
6090 */
Owen Taylor3473f882001-02-23 17:55:21 +00006091 i = (int) in;
6092 if (((double)i) != in) i++;
6093
Owen Taylor3473f882001-02-23 17:55:21 +00006094 l = (int) le;
6095 if (((double)l) != le) l++;
6096
Daniel Veillard97ac1312001-05-30 19:14:17 +00006097 if (l > m) l=m;
Owen Taylor3473f882001-02-23 17:55:21 +00006098
6099 /* number of chars to copy */
6100 l -= i;
6101
Daniel Veillard97ac1312001-05-30 19:14:17 +00006102 ret = xmlUTF8Strsub(str->stringval, i, l);
Owen Taylor3473f882001-02-23 17:55:21 +00006103 if (ret == NULL)
6104 valuePush(ctxt, xmlXPathNewCString(""));
6105 else {
6106 valuePush(ctxt, xmlXPathNewString(ret));
6107 xmlFree(ret);
6108 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006109
Owen Taylor3473f882001-02-23 17:55:21 +00006110 xmlXPathFreeObject(str);
6111}
6112
6113/**
6114 * xmlXPathSubstringBeforeFunction:
6115 * @ctxt: the XPath Parser context
6116 * @nargs: the number of arguments
6117 *
6118 * Implement the substring-before() XPath function
6119 * string substring-before(string, string)
6120 * The substring-before function returns the substring of the first
6121 * argument string that precedes the first occurrence of the second
6122 * argument string in the first argument string, or the empty string
6123 * if the first argument string does not contain the second argument
6124 * string. For example, substring-before("1999/04/01","/") returns 1999.
6125 */
6126void
6127xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6128 xmlXPathObjectPtr str;
6129 xmlXPathObjectPtr find;
6130 xmlBufferPtr target;
6131 const xmlChar *point;
6132 int offset;
6133
6134 CHECK_ARITY(2);
6135 CAST_TO_STRING;
6136 find = valuePop(ctxt);
6137 CAST_TO_STRING;
6138 str = valuePop(ctxt);
6139
6140 target = xmlBufferCreate();
6141 if (target) {
6142 point = xmlStrstr(str->stringval, find->stringval);
6143 if (point) {
6144 offset = (int)(point - str->stringval);
6145 xmlBufferAdd(target, str->stringval, offset);
6146 }
6147 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6148 xmlBufferFree(target);
6149 }
6150
6151 xmlXPathFreeObject(str);
6152 xmlXPathFreeObject(find);
6153}
6154
6155/**
6156 * xmlXPathSubstringAfterFunction:
6157 * @ctxt: the XPath Parser context
6158 * @nargs: the number of arguments
6159 *
6160 * Implement the substring-after() XPath function
6161 * string substring-after(string, string)
6162 * The substring-after function returns the substring of the first
6163 * argument string that follows the first occurrence of the second
6164 * argument string in the first argument string, or the empty stringi
6165 * if the first argument string does not contain the second argument
6166 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6167 * and substring-after("1999/04/01","19") returns 99/04/01.
6168 */
6169void
6170xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6171 xmlXPathObjectPtr str;
6172 xmlXPathObjectPtr find;
6173 xmlBufferPtr target;
6174 const xmlChar *point;
6175 int offset;
6176
6177 CHECK_ARITY(2);
6178 CAST_TO_STRING;
6179 find = valuePop(ctxt);
6180 CAST_TO_STRING;
6181 str = valuePop(ctxt);
6182
6183 target = xmlBufferCreate();
6184 if (target) {
6185 point = xmlStrstr(str->stringval, find->stringval);
6186 if (point) {
6187 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6188 xmlBufferAdd(target, &str->stringval[offset],
6189 xmlStrlen(str->stringval) - offset);
6190 }
6191 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6192 xmlBufferFree(target);
6193 }
6194
6195 xmlXPathFreeObject(str);
6196 xmlXPathFreeObject(find);
6197}
6198
6199/**
6200 * xmlXPathNormalizeFunction:
6201 * @ctxt: the XPath Parser context
6202 * @nargs: the number of arguments
6203 *
6204 * Implement the normalize-space() XPath function
6205 * string normalize-space(string?)
6206 * The normalize-space function returns the argument string with white
6207 * space normalized by stripping leading and trailing whitespace
6208 * and replacing sequences of whitespace characters by a single
6209 * space. Whitespace characters are the same allowed by the S production
6210 * in XML. If the argument is omitted, it defaults to the context
6211 * node converted to a string, in other words the value of the context node.
6212 */
6213void
6214xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6215 xmlXPathObjectPtr obj = NULL;
6216 xmlChar *source = NULL;
6217 xmlBufferPtr target;
6218 xmlChar blank;
6219
6220 if (nargs == 0) {
6221 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006222 valuePush(ctxt,
6223 xmlXPathWrapString(
6224 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006225 nargs = 1;
6226 }
6227
6228 CHECK_ARITY(1);
6229 CAST_TO_STRING;
6230 CHECK_TYPE(XPATH_STRING);
6231 obj = valuePop(ctxt);
6232 source = obj->stringval;
6233
6234 target = xmlBufferCreate();
6235 if (target && source) {
6236
6237 /* Skip leading whitespaces */
6238 while (IS_BLANK(*source))
6239 source++;
6240
6241 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6242 blank = 0;
6243 while (*source) {
6244 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006245 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006246 } else {
6247 if (blank) {
6248 xmlBufferAdd(target, &blank, 1);
6249 blank = 0;
6250 }
6251 xmlBufferAdd(target, source, 1);
6252 }
6253 source++;
6254 }
6255
6256 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6257 xmlBufferFree(target);
6258 }
6259 xmlXPathFreeObject(obj);
6260}
6261
6262/**
6263 * xmlXPathTranslateFunction:
6264 * @ctxt: the XPath Parser context
6265 * @nargs: the number of arguments
6266 *
6267 * Implement the translate() XPath function
6268 * string translate(string, string, string)
6269 * The translate function returns the first argument string with
6270 * occurrences of characters in the second argument string replaced
6271 * by the character at the corresponding position in the third argument
6272 * string. For example, translate("bar","abc","ABC") returns the string
6273 * BAr. If there is a character in the second argument string with no
6274 * character at a corresponding position in the third argument string
6275 * (because the second argument string is longer than the third argument
6276 * string), then occurrences of that character in the first argument
6277 * string are removed. For example, translate("--aaa--","abc-","ABC")
6278 * returns "AAA". If a character occurs more than once in second
6279 * argument string, then the first occurrence determines the replacement
6280 * character. If the third argument string is longer than the second
6281 * argument string, then excess characters are ignored.
6282 */
6283void
6284xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006285 xmlXPathObjectPtr str;
6286 xmlXPathObjectPtr from;
6287 xmlXPathObjectPtr to;
6288 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006289 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006290 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006291 xmlChar *point;
6292 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006293
Daniel Veillarde043ee12001-04-16 14:08:07 +00006294 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006295
Daniel Veillarde043ee12001-04-16 14:08:07 +00006296 CAST_TO_STRING;
6297 to = valuePop(ctxt);
6298 CAST_TO_STRING;
6299 from = valuePop(ctxt);
6300 CAST_TO_STRING;
6301 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006302
Daniel Veillarde043ee12001-04-16 14:08:07 +00006303 target = xmlBufferCreate();
6304 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006305 max = xmlUTF8Strlen(to->stringval);
6306 for (cptr = str->stringval; (ch=*cptr); ) {
6307 offset = xmlUTF8Strloc(from->stringval, cptr);
6308 if (offset >= 0) {
6309 if (offset < max) {
6310 point = xmlUTF8Strpos(to->stringval, offset);
6311 if (point)
6312 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6313 }
6314 } else
6315 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6316
6317 /* Step to next character in input */
6318 cptr++;
6319 if ( ch & 0x80 ) {
6320 /* if not simple ascii, verify proper format */
6321 if ( (ch & 0xc0) != 0xc0 ) {
6322 xmlGenericError(xmlGenericErrorContext,
6323 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6324 break;
6325 }
6326 /* then skip over remaining bytes for this char */
6327 while ( (ch <<= 1) & 0x80 )
6328 if ( (*cptr++ & 0xc0) != 0x80 ) {
6329 xmlGenericError(xmlGenericErrorContext,
6330 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6331 break;
6332 }
6333 if (ch & 0x80) /* must have had error encountered */
6334 break;
6335 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006336 }
Owen Taylor3473f882001-02-23 17:55:21 +00006337 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006338 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6339 xmlBufferFree(target);
6340 xmlXPathFreeObject(str);
6341 xmlXPathFreeObject(from);
6342 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006343}
6344
6345/**
6346 * xmlXPathBooleanFunction:
6347 * @ctxt: the XPath Parser context
6348 * @nargs: the number of arguments
6349 *
6350 * Implement the boolean() XPath function
6351 * boolean boolean(object)
6352 * he boolean function converts its argument to a boolean as follows:
6353 * - a number is true if and only if it is neither positive or
6354 * negative zero nor NaN
6355 * - a node-set is true if and only if it is non-empty
6356 * - a string is true if and only if its length is non-zero
6357 */
6358void
6359xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6360 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006361
6362 CHECK_ARITY(1);
6363 cur = valuePop(ctxt);
6364 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006365 cur = xmlXPathConvertBoolean(cur);
6366 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006367}
6368
6369/**
6370 * xmlXPathNotFunction:
6371 * @ctxt: the XPath Parser context
6372 * @nargs: the number of arguments
6373 *
6374 * Implement the not() XPath function
6375 * boolean not(boolean)
6376 * The not function returns true if its argument is false,
6377 * and false otherwise.
6378 */
6379void
6380xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6381 CHECK_ARITY(1);
6382 CAST_TO_BOOLEAN;
6383 CHECK_TYPE(XPATH_BOOLEAN);
6384 ctxt->value->boolval = ! ctxt->value->boolval;
6385}
6386
6387/**
6388 * xmlXPathTrueFunction:
6389 * @ctxt: the XPath Parser context
6390 * @nargs: the number of arguments
6391 *
6392 * Implement the true() XPath function
6393 * boolean true()
6394 */
6395void
6396xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6397 CHECK_ARITY(0);
6398 valuePush(ctxt, xmlXPathNewBoolean(1));
6399}
6400
6401/**
6402 * xmlXPathFalseFunction:
6403 * @ctxt: the XPath Parser context
6404 * @nargs: the number of arguments
6405 *
6406 * Implement the false() XPath function
6407 * boolean false()
6408 */
6409void
6410xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6411 CHECK_ARITY(0);
6412 valuePush(ctxt, xmlXPathNewBoolean(0));
6413}
6414
6415/**
6416 * xmlXPathLangFunction:
6417 * @ctxt: the XPath Parser context
6418 * @nargs: the number of arguments
6419 *
6420 * Implement the lang() XPath function
6421 * boolean lang(string)
6422 * The lang function returns true or false depending on whether the
6423 * language of the context node as specified by xml:lang attributes
6424 * is the same as or is a sublanguage of the language specified by
6425 * the argument string. The language of the context node is determined
6426 * by the value of the xml:lang attribute on the context node, or, if
6427 * the context node has no xml:lang attribute, by the value of the
6428 * xml:lang attribute on the nearest ancestor of the context node that
6429 * has an xml:lang attribute. If there is no such attribute, then lang
6430 * returns false. If there is such an attribute, then lang returns
6431 * true if the attribute value is equal to the argument ignoring case,
6432 * or if there is some suffix starting with - such that the attribute
6433 * value is equal to the argument ignoring that suffix of the attribute
6434 * value and ignoring case.
6435 */
6436void
6437xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6438 xmlXPathObjectPtr val;
6439 const xmlChar *theLang;
6440 const xmlChar *lang;
6441 int ret = 0;
6442 int i;
6443
6444 CHECK_ARITY(1);
6445 CAST_TO_STRING;
6446 CHECK_TYPE(XPATH_STRING);
6447 val = valuePop(ctxt);
6448 lang = val->stringval;
6449 theLang = xmlNodeGetLang(ctxt->context->node);
6450 if ((theLang != NULL) && (lang != NULL)) {
6451 for (i = 0;lang[i] != 0;i++)
6452 if (toupper(lang[i]) != toupper(theLang[i]))
6453 goto not_equal;
6454 ret = 1;
6455 }
6456not_equal:
6457 xmlXPathFreeObject(val);
6458 valuePush(ctxt, xmlXPathNewBoolean(ret));
6459}
6460
6461/**
6462 * xmlXPathNumberFunction:
6463 * @ctxt: the XPath Parser context
6464 * @nargs: the number of arguments
6465 *
6466 * Implement the number() XPath function
6467 * number number(object?)
6468 */
6469void
6470xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6471 xmlXPathObjectPtr cur;
6472 double res;
6473
6474 if (nargs == 0) {
6475 if (ctxt->context->node == NULL) {
6476 valuePush(ctxt, xmlXPathNewFloat(0.0));
6477 } else {
6478 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6479
6480 res = xmlXPathStringEvalNumber(content);
6481 valuePush(ctxt, xmlXPathNewFloat(res));
6482 xmlFree(content);
6483 }
6484 return;
6485 }
6486
6487 CHECK_ARITY(1);
6488 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006489 cur = xmlXPathConvertNumber(cur);
6490 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006491}
6492
6493/**
6494 * xmlXPathSumFunction:
6495 * @ctxt: the XPath Parser context
6496 * @nargs: the number of arguments
6497 *
6498 * Implement the sum() XPath function
6499 * number sum(node-set)
6500 * The sum function returns the sum of the values of the nodes in
6501 * the argument node-set.
6502 */
6503void
6504xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6505 xmlXPathObjectPtr cur;
6506 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006507 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00006508
6509 CHECK_ARITY(1);
6510 if ((ctxt->value == NULL) ||
6511 ((ctxt->value->type != XPATH_NODESET) &&
6512 (ctxt->value->type != XPATH_XSLT_TREE)))
6513 XP_ERROR(XPATH_INVALID_TYPE);
6514 cur = valuePop(ctxt);
6515
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006516 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006517 valuePush(ctxt, xmlXPathNewFloat(0.0));
6518 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006519 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
6520 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006521 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006522 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00006523 }
6524 xmlXPathFreeObject(cur);
6525}
6526
6527/**
6528 * xmlXPathFloorFunction:
6529 * @ctxt: the XPath Parser context
6530 * @nargs: the number of arguments
6531 *
6532 * Implement the floor() XPath function
6533 * number floor(number)
6534 * The floor function returns the largest (closest to positive infinity)
6535 * number that is not greater than the argument and that is an integer.
6536 */
6537void
6538xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006539 double f;
6540
Owen Taylor3473f882001-02-23 17:55:21 +00006541 CHECK_ARITY(1);
6542 CAST_TO_NUMBER;
6543 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006544
6545 f = (double)((int) ctxt->value->floatval);
6546 if (f != ctxt->value->floatval) {
6547 if (ctxt->value->floatval > 0)
6548 ctxt->value->floatval = f;
6549 else
6550 ctxt->value->floatval = f - 1;
6551 }
Owen Taylor3473f882001-02-23 17:55:21 +00006552}
6553
6554/**
6555 * xmlXPathCeilingFunction:
6556 * @ctxt: the XPath Parser context
6557 * @nargs: the number of arguments
6558 *
6559 * Implement the ceiling() XPath function
6560 * number ceiling(number)
6561 * The ceiling function returns the smallest (closest to negative infinity)
6562 * number that is not less than the argument and that is an integer.
6563 */
6564void
6565xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6566 double f;
6567
6568 CHECK_ARITY(1);
6569 CAST_TO_NUMBER;
6570 CHECK_TYPE(XPATH_NUMBER);
6571
6572#if 0
6573 ctxt->value->floatval = ceil(ctxt->value->floatval);
6574#else
6575 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006576 if (f != ctxt->value->floatval) {
6577 if (ctxt->value->floatval > 0)
6578 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00006579 else {
6580 if (ctxt->value->floatval < 0 && f == 0)
6581 ctxt->value->floatval = xmlXPathNZERO;
6582 else
6583 ctxt->value->floatval = f;
6584 }
6585
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006586 }
Owen Taylor3473f882001-02-23 17:55:21 +00006587#endif
6588}
6589
6590/**
6591 * xmlXPathRoundFunction:
6592 * @ctxt: the XPath Parser context
6593 * @nargs: the number of arguments
6594 *
6595 * Implement the round() XPath function
6596 * number round(number)
6597 * The round function returns the number that is closest to the
6598 * argument and that is an integer. If there are two such numbers,
6599 * then the one that is even is returned.
6600 */
6601void
6602xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6603 double f;
6604
6605 CHECK_ARITY(1);
6606 CAST_TO_NUMBER;
6607 CHECK_TYPE(XPATH_NUMBER);
6608
Daniel Veillardcda96922001-08-21 10:56:31 +00006609 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
6610 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
6611 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00006612 (ctxt->value->floatval == 0.0))
6613 return;
6614
Owen Taylor3473f882001-02-23 17:55:21 +00006615 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006616 if (ctxt->value->floatval < 0) {
6617 if (ctxt->value->floatval < f - 0.5)
6618 ctxt->value->floatval = f - 1;
6619 else
6620 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00006621 if (ctxt->value->floatval == 0)
6622 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006623 } else {
6624 if (ctxt->value->floatval < f + 0.5)
6625 ctxt->value->floatval = f;
6626 else
6627 ctxt->value->floatval = f + 1;
6628 }
Owen Taylor3473f882001-02-23 17:55:21 +00006629}
6630
6631/************************************************************************
6632 * *
6633 * The Parser *
6634 * *
6635 ************************************************************************/
6636
6637/*
6638 * a couple of forward declarations since we use a recursive call based
6639 * implementation.
6640 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006641static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006642static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006643static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006644#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006645static void xmlXPathCompRelLocationPath(xmlXPathParserContextPtr ctxt);
6646#define xmlXPathCompRelativeLocationPath xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00006647#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006648static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006649#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00006650static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
6651 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00006652
6653/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00006654 * xmlXPathCurrentChar:
6655 * @ctxt: the XPath parser context
6656 * @cur: pointer to the beginning of the char
6657 * @len: pointer to the length of the char read
6658 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006659 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00006660 * bytes in the input buffer.
6661 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006662 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00006663 */
6664
6665static int
6666xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
6667 unsigned char c;
6668 unsigned int val;
6669 const xmlChar *cur;
6670
6671 if (ctxt == NULL)
6672 return(0);
6673 cur = ctxt->cur;
6674
6675 /*
6676 * We are supposed to handle UTF8, check it's valid
6677 * From rfc2044: encoding of the Unicode values on UTF-8:
6678 *
6679 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
6680 * 0000 0000-0000 007F 0xxxxxxx
6681 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
6682 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
6683 *
6684 * Check for the 0x110000 limit too
6685 */
6686 c = *cur;
6687 if (c & 0x80) {
6688 if ((cur[1] & 0xc0) != 0x80)
6689 goto encoding_error;
6690 if ((c & 0xe0) == 0xe0) {
6691
6692 if ((cur[2] & 0xc0) != 0x80)
6693 goto encoding_error;
6694 if ((c & 0xf0) == 0xf0) {
6695 if (((c & 0xf8) != 0xf0) ||
6696 ((cur[3] & 0xc0) != 0x80))
6697 goto encoding_error;
6698 /* 4-byte code */
6699 *len = 4;
6700 val = (cur[0] & 0x7) << 18;
6701 val |= (cur[1] & 0x3f) << 12;
6702 val |= (cur[2] & 0x3f) << 6;
6703 val |= cur[3] & 0x3f;
6704 } else {
6705 /* 3-byte code */
6706 *len = 3;
6707 val = (cur[0] & 0xf) << 12;
6708 val |= (cur[1] & 0x3f) << 6;
6709 val |= cur[2] & 0x3f;
6710 }
6711 } else {
6712 /* 2-byte code */
6713 *len = 2;
6714 val = (cur[0] & 0x1f) << 6;
6715 val |= cur[1] & 0x3f;
6716 }
6717 if (!IS_CHAR(val)) {
6718 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
6719 }
6720 return(val);
6721 } else {
6722 /* 1-byte code */
6723 *len = 1;
6724 return((int) *cur);
6725 }
6726encoding_error:
6727 /*
6728 * If we detect an UTF8 error that probably mean that the
6729 * input encoding didn't get properly advertized in the
6730 * declaration header. Report the error and switch the encoding
6731 * to ISO-Latin-1 (if you don't like this policy, just declare the
6732 * encoding !)
6733 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00006734 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00006735 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00006736}
6737
6738/**
Owen Taylor3473f882001-02-23 17:55:21 +00006739 * xmlXPathParseNCName:
6740 * @ctxt: the XPath Parser context
6741 *
6742 * parse an XML namespace non qualified name.
6743 *
6744 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
6745 *
6746 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
6747 * CombiningChar | Extender
6748 *
6749 * Returns the namespace name or NULL
6750 */
6751
6752xmlChar *
6753xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00006754 const xmlChar *in;
6755 xmlChar *ret;
6756 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006757
Daniel Veillard2156a562001-04-28 12:24:34 +00006758 /*
6759 * Accelerator for simple ASCII names
6760 */
6761 in = ctxt->cur;
6762 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6763 ((*in >= 0x41) && (*in <= 0x5A)) ||
6764 (*in == '_')) {
6765 in++;
6766 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6767 ((*in >= 0x41) && (*in <= 0x5A)) ||
6768 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00006769 (*in == '_') || (*in == '.') ||
6770 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00006771 in++;
6772 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
6773 (*in == '[') || (*in == ']') || (*in == ':') ||
6774 (*in == '@') || (*in == '*')) {
6775 count = in - ctxt->cur;
6776 if (count == 0)
6777 return(NULL);
6778 ret = xmlStrndup(ctxt->cur, count);
6779 ctxt->cur = in;
6780 return(ret);
6781 }
6782 }
6783 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00006784}
6785
Daniel Veillard2156a562001-04-28 12:24:34 +00006786
Owen Taylor3473f882001-02-23 17:55:21 +00006787/**
6788 * xmlXPathParseQName:
6789 * @ctxt: the XPath Parser context
6790 * @prefix: a xmlChar **
6791 *
6792 * parse an XML qualified name
6793 *
6794 * [NS 5] QName ::= (Prefix ':')? LocalPart
6795 *
6796 * [NS 6] Prefix ::= NCName
6797 *
6798 * [NS 7] LocalPart ::= NCName
6799 *
6800 * Returns the function returns the local part, and prefix is updated
6801 * to get the Prefix if any.
6802 */
6803
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006804static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006805xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
6806 xmlChar *ret = NULL;
6807
6808 *prefix = NULL;
6809 ret = xmlXPathParseNCName(ctxt);
6810 if (CUR == ':') {
6811 *prefix = ret;
6812 NEXT;
6813 ret = xmlXPathParseNCName(ctxt);
6814 }
6815 return(ret);
6816}
6817
6818/**
6819 * xmlXPathParseName:
6820 * @ctxt: the XPath Parser context
6821 *
6822 * parse an XML name
6823 *
6824 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
6825 * CombiningChar | Extender
6826 *
6827 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
6828 *
6829 * Returns the namespace name or NULL
6830 */
6831
6832xmlChar *
6833xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006834 const xmlChar *in;
6835 xmlChar *ret;
6836 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006837
Daniel Veillard61d80a22001-04-27 17:13:01 +00006838 /*
6839 * Accelerator for simple ASCII names
6840 */
6841 in = ctxt->cur;
6842 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6843 ((*in >= 0x41) && (*in <= 0x5A)) ||
6844 (*in == '_') || (*in == ':')) {
6845 in++;
6846 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6847 ((*in >= 0x41) && (*in <= 0x5A)) ||
6848 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00006849 (*in == '_') || (*in == '-') ||
6850 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00006851 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00006852 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006853 count = in - ctxt->cur;
6854 ret = xmlStrndup(ctxt->cur, count);
6855 ctxt->cur = in;
6856 return(ret);
6857 }
6858 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006859 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00006860}
6861
Daniel Veillard61d80a22001-04-27 17:13:01 +00006862static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00006863xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006864 xmlChar buf[XML_MAX_NAMELEN + 5];
6865 int len = 0, l;
6866 int c;
6867
6868 /*
6869 * Handler for more complex cases
6870 */
6871 c = CUR_CHAR(l);
6872 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00006873 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
6874 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00006875 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00006876 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006877 return(NULL);
6878 }
6879
6880 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
6881 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
6882 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00006883 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00006884 (IS_COMBINING(c)) ||
6885 (IS_EXTENDER(c)))) {
6886 COPY_BUF(l,buf,len,c);
6887 NEXTL(l);
6888 c = CUR_CHAR(l);
6889 if (len >= XML_MAX_NAMELEN) {
6890 /*
6891 * Okay someone managed to make a huge name, so he's ready to pay
6892 * for the processing speed.
6893 */
6894 xmlChar *buffer;
6895 int max = len * 2;
6896
6897 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
6898 if (buffer == NULL) {
6899 XP_ERROR0(XPATH_MEMORY_ERROR);
6900 }
6901 memcpy(buffer, buf, len);
6902 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
6903 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00006904 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00006905 (IS_COMBINING(c)) ||
6906 (IS_EXTENDER(c))) {
6907 if (len + 10 > max) {
6908 max *= 2;
6909 buffer = (xmlChar *) xmlRealloc(buffer,
6910 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00006911 if (buffer == NULL) {
6912 XP_ERROR0(XPATH_MEMORY_ERROR);
6913 }
6914 }
6915 COPY_BUF(l,buffer,len,c);
6916 NEXTL(l);
6917 c = CUR_CHAR(l);
6918 }
6919 buffer[len] = 0;
6920 return(buffer);
6921 }
6922 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006923 if (len == 0)
6924 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00006925 return(xmlStrndup(buf, len));
6926}
Owen Taylor3473f882001-02-23 17:55:21 +00006927/**
6928 * xmlXPathStringEvalNumber:
6929 * @str: A string to scan
6930 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00006931 * [30a] Float ::= Number ('e' Digits?)?
6932 *
Owen Taylor3473f882001-02-23 17:55:21 +00006933 * [30] Number ::= Digits ('.' Digits?)?
6934 * | '.' Digits
6935 * [31] Digits ::= [0-9]+
6936 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006937 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00006938 * In complement of the Number expression, this function also handles
6939 * negative values : '-' Number.
6940 *
6941 * Returns the double value.
6942 */
6943double
6944xmlXPathStringEvalNumber(const xmlChar *str) {
6945 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00006946 double ret;
Owen Taylor3473f882001-02-23 17:55:21 +00006947 double mult = 1;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006948 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006949 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006950 int exponent = 0;
6951 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006952#ifdef __GNUC__
6953 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00006954 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006955#endif
Bjorn Reese70a9da52001-04-21 16:57:29 +00006956
Owen Taylor3473f882001-02-23 17:55:21 +00006957 while (IS_BLANK(*cur)) cur++;
6958 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
6959 return(xmlXPathNAN);
6960 }
6961 if (*cur == '-') {
6962 isneg = 1;
6963 cur++;
6964 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00006965
6966#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006967 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00006968 * tmp/temp is a workaround against a gcc compiler bug
6969 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006970 */
Daniel Veillard7b416132002-03-07 08:36:03 +00006971 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006972 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00006973 ret = ret * 10;
6974 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00006975 ok = 1;
6976 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00006977 temp = (double) tmp;
6978 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00006979 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00006980#else
Daniel Veillard7b416132002-03-07 08:36:03 +00006981 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006982 while ((*cur >= '0') && (*cur <= '9')) {
6983 ret = ret * 10 + (*cur - '0');
6984 ok = 1;
6985 cur++;
6986 }
6987#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006988
Owen Taylor3473f882001-02-23 17:55:21 +00006989 if (*cur == '.') {
6990 cur++;
6991 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
6992 return(xmlXPathNAN);
6993 }
6994 while ((*cur >= '0') && (*cur <= '9')) {
6995 mult /= 10;
6996 ret = ret + (*cur - '0') * mult;
6997 cur++;
6998 }
6999 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007000 if ((*cur == 'e') || (*cur == 'E')) {
7001 cur++;
7002 if (*cur == '-') {
7003 is_exponent_negative = 1;
7004 cur++;
7005 }
7006 while ((*cur >= '0') && (*cur <= '9')) {
7007 exponent = exponent * 10 + (*cur - '0');
7008 cur++;
7009 }
7010 }
Owen Taylor3473f882001-02-23 17:55:21 +00007011 while (IS_BLANK(*cur)) cur++;
7012 if (*cur != 0) return(xmlXPathNAN);
7013 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007014 if (is_exponent_negative) exponent = -exponent;
7015 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007016 return(ret);
7017}
7018
7019/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007020 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007021 * @ctxt: the XPath Parser context
7022 *
7023 * [30] Number ::= Digits ('.' Digits?)?
7024 * | '.' Digits
7025 * [31] Digits ::= [0-9]+
7026 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007027 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007028 *
7029 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007030static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007031xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7032{
Owen Taylor3473f882001-02-23 17:55:21 +00007033 double ret = 0.0;
7034 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007035 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007036 int exponent = 0;
7037 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007038#ifdef __GNUC__
7039 unsigned long tmp = 0;
7040 double temp;
7041#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007042
7043 CHECK_ERROR;
7044 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7045 XP_ERROR(XPATH_NUMBER_ERROR);
7046 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007047#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007048 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007049 * tmp/temp is a workaround against a gcc compiler bug
7050 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007051 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007052 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007053 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007054 ret = ret * 10;
7055 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007056 ok = 1;
7057 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007058 temp = (double) tmp;
7059 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007060 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007061#else
7062 ret = 0;
7063 while ((CUR >= '0') && (CUR <= '9')) {
7064 ret = ret * 10 + (CUR - '0');
7065 ok = 1;
7066 NEXT;
7067 }
7068#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007069 if (CUR == '.') {
7070 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007071 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7072 XP_ERROR(XPATH_NUMBER_ERROR);
7073 }
7074 while ((CUR >= '0') && (CUR <= '9')) {
7075 mult /= 10;
7076 ret = ret + (CUR - '0') * mult;
7077 NEXT;
7078 }
Owen Taylor3473f882001-02-23 17:55:21 +00007079 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007080 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007081 NEXT;
7082 if (CUR == '-') {
7083 is_exponent_negative = 1;
7084 NEXT;
7085 }
7086 while ((CUR >= '0') && (CUR <= '9')) {
7087 exponent = exponent * 10 + (CUR - '0');
7088 NEXT;
7089 }
7090 if (is_exponent_negative)
7091 exponent = -exponent;
7092 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007093 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007094 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007095 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007096}
7097
7098/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007099 * xmlXPathParseLiteral:
7100 * @ctxt: the XPath Parser context
7101 *
7102 * Parse a Literal
7103 *
7104 * [29] Literal ::= '"' [^"]* '"'
7105 * | "'" [^']* "'"
7106 *
7107 * Returns the value found or NULL in case of error
7108 */
7109static xmlChar *
7110xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7111 const xmlChar *q;
7112 xmlChar *ret = NULL;
7113
7114 if (CUR == '"') {
7115 NEXT;
7116 q = CUR_PTR;
7117 while ((IS_CHAR(CUR)) && (CUR != '"'))
7118 NEXT;
7119 if (!IS_CHAR(CUR)) {
7120 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7121 } else {
7122 ret = xmlStrndup(q, CUR_PTR - q);
7123 NEXT;
7124 }
7125 } else if (CUR == '\'') {
7126 NEXT;
7127 q = CUR_PTR;
7128 while ((IS_CHAR(CUR)) && (CUR != '\''))
7129 NEXT;
7130 if (!IS_CHAR(CUR)) {
7131 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7132 } else {
7133 ret = xmlStrndup(q, CUR_PTR - q);
7134 NEXT;
7135 }
7136 } else {
7137 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7138 }
7139 return(ret);
7140}
7141
7142/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007143 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007144 * @ctxt: the XPath Parser context
7145 *
7146 * Parse a Literal and push it on the stack.
7147 *
7148 * [29] Literal ::= '"' [^"]* '"'
7149 * | "'" [^']* "'"
7150 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007151 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007152 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007153static void
7154xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007155 const xmlChar *q;
7156 xmlChar *ret = NULL;
7157
7158 if (CUR == '"') {
7159 NEXT;
7160 q = CUR_PTR;
7161 while ((IS_CHAR(CUR)) && (CUR != '"'))
7162 NEXT;
7163 if (!IS_CHAR(CUR)) {
7164 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7165 } else {
7166 ret = xmlStrndup(q, CUR_PTR - q);
7167 NEXT;
7168 }
7169 } else if (CUR == '\'') {
7170 NEXT;
7171 q = CUR_PTR;
7172 while ((IS_CHAR(CUR)) && (CUR != '\''))
7173 NEXT;
7174 if (!IS_CHAR(CUR)) {
7175 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7176 } else {
7177 ret = xmlStrndup(q, CUR_PTR - q);
7178 NEXT;
7179 }
7180 } else {
7181 XP_ERROR(XPATH_START_LITERAL_ERROR);
7182 }
7183 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007184 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7185 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007186 xmlFree(ret);
7187}
7188
7189/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007190 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007191 * @ctxt: the XPath Parser context
7192 *
7193 * Parse a VariableReference, evaluate it and push it on the stack.
7194 *
7195 * The variable bindings consist of a mapping from variable names
7196 * to variable values. The value of a variable is an object, which
7197 * of any of the types that are possible for the value of an expression,
7198 * and may also be of additional types not specified here.
7199 *
7200 * Early evaluation is possible since:
7201 * The variable bindings [...] used to evaluate a subexpression are
7202 * always the same as those used to evaluate the containing expression.
7203 *
7204 * [36] VariableReference ::= '$' QName
7205 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007206static void
7207xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007208 xmlChar *name;
7209 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007210
7211 SKIP_BLANKS;
7212 if (CUR != '$') {
7213 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7214 }
7215 NEXT;
7216 name = xmlXPathParseQName(ctxt, &prefix);
7217 if (name == NULL) {
7218 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7219 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007220 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007221 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7222 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007223 SKIP_BLANKS;
7224}
7225
7226/**
7227 * xmlXPathIsNodeType:
7228 * @ctxt: the XPath Parser context
7229 * @name: a name string
7230 *
7231 * Is the name given a NodeType one.
7232 *
7233 * [38] NodeType ::= 'comment'
7234 * | 'text'
7235 * | 'processing-instruction'
7236 * | 'node'
7237 *
7238 * Returns 1 if true 0 otherwise
7239 */
7240int
7241xmlXPathIsNodeType(const xmlChar *name) {
7242 if (name == NULL)
7243 return(0);
7244
Daniel Veillard1971ee22002-01-31 20:29:19 +00007245 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007246 return(1);
7247 if (xmlStrEqual(name, BAD_CAST "text"))
7248 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007249 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007250 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007251 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007252 return(1);
7253 return(0);
7254}
7255
7256/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007257 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007258 * @ctxt: the XPath Parser context
7259 *
7260 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7261 * [17] Argument ::= Expr
7262 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007263 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007264 * pushed on the stack
7265 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007266static void
7267xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007268 xmlChar *name;
7269 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007270 int nbargs = 0;
7271
7272 name = xmlXPathParseQName(ctxt, &prefix);
7273 if (name == NULL) {
7274 XP_ERROR(XPATH_EXPR_ERROR);
7275 }
7276 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007277#ifdef DEBUG_EXPR
7278 if (prefix == NULL)
7279 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7280 name);
7281 else
7282 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7283 prefix, name);
7284#endif
7285
Owen Taylor3473f882001-02-23 17:55:21 +00007286 if (CUR != '(') {
7287 XP_ERROR(XPATH_EXPR_ERROR);
7288 }
7289 NEXT;
7290 SKIP_BLANKS;
7291
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007292 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007293 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007294 int op1 = ctxt->comp->last;
7295 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007296 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007297 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007298 nbargs++;
7299 if (CUR == ')') break;
7300 if (CUR != ',') {
7301 XP_ERROR(XPATH_EXPR_ERROR);
7302 }
7303 NEXT;
7304 SKIP_BLANKS;
7305 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007306 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7307 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007308 NEXT;
7309 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007310}
7311
7312/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007313 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007314 * @ctxt: the XPath Parser context
7315 *
7316 * [15] PrimaryExpr ::= VariableReference
7317 * | '(' Expr ')'
7318 * | Literal
7319 * | Number
7320 * | FunctionCall
7321 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007322 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007323 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007324static void
7325xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007326 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007327 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007328 else if (CUR == '(') {
7329 NEXT;
7330 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007331 xmlXPathCompileExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007332 if (CUR != ')') {
7333 XP_ERROR(XPATH_EXPR_ERROR);
7334 }
7335 NEXT;
7336 SKIP_BLANKS;
7337 } else if (IS_DIGIT(CUR)) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007338 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007339 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007340 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007341 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007342 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007343 }
7344 SKIP_BLANKS;
7345}
7346
7347/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007348 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007349 * @ctxt: the XPath Parser context
7350 *
7351 * [20] FilterExpr ::= PrimaryExpr
7352 * | FilterExpr Predicate
7353 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007354 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007355 * Square brackets are used to filter expressions in the same way that
7356 * they are used in location paths. It is an error if the expression to
7357 * be filtered does not evaluate to a node-set. The context node list
7358 * used for evaluating the expression in square brackets is the node-set
7359 * to be filtered listed in document order.
7360 */
7361
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007362static void
7363xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
7364 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007365 CHECK_ERROR;
7366 SKIP_BLANKS;
7367
7368 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007369 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00007370 SKIP_BLANKS;
7371 }
7372
7373
7374}
7375
7376/**
7377 * xmlXPathScanName:
7378 * @ctxt: the XPath Parser context
7379 *
7380 * Trickery: parse an XML name but without consuming the input flow
7381 * Needed to avoid insanity in the parser state.
7382 *
7383 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7384 * CombiningChar | Extender
7385 *
7386 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7387 *
7388 * [6] Names ::= Name (S Name)*
7389 *
7390 * Returns the Name parsed or NULL
7391 */
7392
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007393static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007394xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7395 xmlChar buf[XML_MAX_NAMELEN];
7396 int len = 0;
7397
7398 SKIP_BLANKS;
7399 if (!IS_LETTER(CUR) && (CUR != '_') &&
7400 (CUR != ':')) {
7401 return(NULL);
7402 }
7403
7404 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7405 (NXT(len) == '.') || (NXT(len) == '-') ||
7406 (NXT(len) == '_') || (NXT(len) == ':') ||
7407 (IS_COMBINING(NXT(len))) ||
7408 (IS_EXTENDER(NXT(len)))) {
7409 buf[len] = NXT(len);
7410 len++;
7411 if (len >= XML_MAX_NAMELEN) {
7412 xmlGenericError(xmlGenericErrorContext,
7413 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
7414 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7415 (NXT(len) == '.') || (NXT(len) == '-') ||
7416 (NXT(len) == '_') || (NXT(len) == ':') ||
7417 (IS_COMBINING(NXT(len))) ||
7418 (IS_EXTENDER(NXT(len))))
7419 len++;
7420 break;
7421 }
7422 }
7423 return(xmlStrndup(buf, len));
7424}
7425
7426/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007427 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007428 * @ctxt: the XPath Parser context
7429 *
7430 * [19] PathExpr ::= LocationPath
7431 * | FilterExpr
7432 * | FilterExpr '/' RelativeLocationPath
7433 * | FilterExpr '//' RelativeLocationPath
7434 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007435 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007436 * The / operator and // operators combine an arbitrary expression
7437 * and a relative location path. It is an error if the expression
7438 * does not evaluate to a node-set.
7439 * The / operator does composition in the same way as when / is
7440 * used in a location path. As in location paths, // is short for
7441 * /descendant-or-self::node()/.
7442 */
7443
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007444static void
7445xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007446 int lc = 1; /* Should we branch to LocationPath ? */
7447 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7448
7449 SKIP_BLANKS;
7450 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
7451 (CUR == '\'') || (CUR == '"')) {
7452 lc = 0;
7453 } else if (CUR == '*') {
7454 /* relative or absolute location path */
7455 lc = 1;
7456 } else if (CUR == '/') {
7457 /* relative or absolute location path */
7458 lc = 1;
7459 } else if (CUR == '@') {
7460 /* relative abbreviated attribute location path */
7461 lc = 1;
7462 } else if (CUR == '.') {
7463 /* relative abbreviated attribute location path */
7464 lc = 1;
7465 } else {
7466 /*
7467 * Problem is finding if we have a name here whether it's:
7468 * - a nodetype
7469 * - a function call in which case it's followed by '('
7470 * - an axis in which case it's followed by ':'
7471 * - a element name
7472 * We do an a priori analysis here rather than having to
7473 * maintain parsed token content through the recursive function
7474 * calls. This looks uglier but makes the code quite easier to
7475 * read/write/debug.
7476 */
7477 SKIP_BLANKS;
7478 name = xmlXPathScanName(ctxt);
7479 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7480#ifdef DEBUG_STEP
7481 xmlGenericError(xmlGenericErrorContext,
7482 "PathExpr: Axis\n");
7483#endif
7484 lc = 1;
7485 xmlFree(name);
7486 } else if (name != NULL) {
7487 int len =xmlStrlen(name);
7488 int blank = 0;
7489
7490
7491 while (NXT(len) != 0) {
7492 if (NXT(len) == '/') {
7493 /* element name */
7494#ifdef DEBUG_STEP
7495 xmlGenericError(xmlGenericErrorContext,
7496 "PathExpr: AbbrRelLocation\n");
7497#endif
7498 lc = 1;
7499 break;
7500 } else if (IS_BLANK(NXT(len))) {
7501 /* skip to next */
7502 blank = 1;
7503 } else if (NXT(len) == ':') {
7504#ifdef DEBUG_STEP
7505 xmlGenericError(xmlGenericErrorContext,
7506 "PathExpr: AbbrRelLocation\n");
7507#endif
7508 lc = 1;
7509 break;
7510 } else if ((NXT(len) == '(')) {
7511 /* Note Type or Function */
7512 if (xmlXPathIsNodeType(name)) {
7513#ifdef DEBUG_STEP
7514 xmlGenericError(xmlGenericErrorContext,
7515 "PathExpr: Type search\n");
7516#endif
7517 lc = 1;
7518 } else {
7519#ifdef DEBUG_STEP
7520 xmlGenericError(xmlGenericErrorContext,
7521 "PathExpr: function call\n");
7522#endif
7523 lc = 0;
7524 }
7525 break;
7526 } else if ((NXT(len) == '[')) {
7527 /* element name */
7528#ifdef DEBUG_STEP
7529 xmlGenericError(xmlGenericErrorContext,
7530 "PathExpr: AbbrRelLocation\n");
7531#endif
7532 lc = 1;
7533 break;
7534 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
7535 (NXT(len) == '=')) {
7536 lc = 1;
7537 break;
7538 } else {
7539 lc = 1;
7540 break;
7541 }
7542 len++;
7543 }
7544 if (NXT(len) == 0) {
7545#ifdef DEBUG_STEP
7546 xmlGenericError(xmlGenericErrorContext,
7547 "PathExpr: AbbrRelLocation\n");
7548#endif
7549 /* element name */
7550 lc = 1;
7551 }
7552 xmlFree(name);
7553 } else {
7554 /* make sure all cases are covered explicitely */
7555 XP_ERROR(XPATH_EXPR_ERROR);
7556 }
7557 }
7558
7559 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007560 if (CUR == '/') {
7561 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
7562 } else {
7563 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007564 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007565 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007566 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007567 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007568 CHECK_ERROR;
7569 if ((CUR == '/') && (NXT(1) == '/')) {
7570 SKIP(2);
7571 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007572
7573 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7574 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
7575 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
7576
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007577 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007578 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007579 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007580 }
7581 }
7582 SKIP_BLANKS;
7583}
7584
7585/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007586 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007587 * @ctxt: the XPath Parser context
7588 *
7589 * [18] UnionExpr ::= PathExpr
7590 * | UnionExpr '|' PathExpr
7591 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007592 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007593 */
7594
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007595static void
7596xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
7597 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007598 CHECK_ERROR;
7599 SKIP_BLANKS;
7600 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007601 int op1 = ctxt->comp->last;
7602 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007603
7604 NEXT;
7605 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007606 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007607
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007608 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
7609
Owen Taylor3473f882001-02-23 17:55:21 +00007610 SKIP_BLANKS;
7611 }
Owen Taylor3473f882001-02-23 17:55:21 +00007612}
7613
7614/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007615 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007616 * @ctxt: the XPath Parser context
7617 *
7618 * [27] UnaryExpr ::= UnionExpr
7619 * | '-' UnaryExpr
7620 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007621 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007622 */
7623
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007624static void
7625xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007626 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007627 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007628
7629 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00007630 while (CUR == '-') {
7631 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007632 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007633 NEXT;
7634 SKIP_BLANKS;
7635 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007636
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007637 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007638 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007639 if (found) {
7640 if (minus)
7641 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
7642 else
7643 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007644 }
7645}
7646
7647/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007648 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007649 * @ctxt: the XPath Parser context
7650 *
7651 * [26] MultiplicativeExpr ::= UnaryExpr
7652 * | MultiplicativeExpr MultiplyOperator UnaryExpr
7653 * | MultiplicativeExpr 'div' UnaryExpr
7654 * | MultiplicativeExpr 'mod' UnaryExpr
7655 * [34] MultiplyOperator ::= '*'
7656 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007657 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007658 */
7659
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007660static void
7661xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
7662 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007663 CHECK_ERROR;
7664 SKIP_BLANKS;
7665 while ((CUR == '*') ||
7666 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
7667 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
7668 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007669 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007670
7671 if (CUR == '*') {
7672 op = 0;
7673 NEXT;
7674 } else if (CUR == 'd') {
7675 op = 1;
7676 SKIP(3);
7677 } else if (CUR == 'm') {
7678 op = 2;
7679 SKIP(3);
7680 }
7681 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007682 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007683 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007684 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007685 SKIP_BLANKS;
7686 }
7687}
7688
7689/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007690 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007691 * @ctxt: the XPath Parser context
7692 *
7693 * [25] AdditiveExpr ::= MultiplicativeExpr
7694 * | AdditiveExpr '+' MultiplicativeExpr
7695 * | AdditiveExpr '-' MultiplicativeExpr
7696 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007697 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007698 */
7699
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007700static void
7701xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007702
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007703 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007704 CHECK_ERROR;
7705 SKIP_BLANKS;
7706 while ((CUR == '+') || (CUR == '-')) {
7707 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007708 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007709
7710 if (CUR == '+') plus = 1;
7711 else plus = 0;
7712 NEXT;
7713 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007714 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007715 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007716 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007717 SKIP_BLANKS;
7718 }
7719}
7720
7721/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007722 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007723 * @ctxt: the XPath Parser context
7724 *
7725 * [24] RelationalExpr ::= AdditiveExpr
7726 * | RelationalExpr '<' AdditiveExpr
7727 * | RelationalExpr '>' AdditiveExpr
7728 * | RelationalExpr '<=' AdditiveExpr
7729 * | RelationalExpr '>=' AdditiveExpr
7730 *
7731 * A <= B > C is allowed ? Answer from James, yes with
7732 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
7733 * which is basically what got implemented.
7734 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007735 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00007736 * on the stack
7737 */
7738
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007739static void
7740xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
7741 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007742 CHECK_ERROR;
7743 SKIP_BLANKS;
7744 while ((CUR == '<') ||
7745 (CUR == '>') ||
7746 ((CUR == '<') && (NXT(1) == '=')) ||
7747 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007748 int inf, strict;
7749 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007750
7751 if (CUR == '<') inf = 1;
7752 else inf = 0;
7753 if (NXT(1) == '=') strict = 0;
7754 else strict = 1;
7755 NEXT;
7756 if (!strict) NEXT;
7757 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007758 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007759 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007760 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00007761 SKIP_BLANKS;
7762 }
7763}
7764
7765/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007766 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007767 * @ctxt: the XPath Parser context
7768 *
7769 * [23] EqualityExpr ::= RelationalExpr
7770 * | EqualityExpr '=' RelationalExpr
7771 * | EqualityExpr '!=' RelationalExpr
7772 *
7773 * A != B != C is allowed ? Answer from James, yes with
7774 * (RelationalExpr = RelationalExpr) = RelationalExpr
7775 * (RelationalExpr != RelationalExpr) != RelationalExpr
7776 * which is basically what got implemented.
7777 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007778 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007779 *
7780 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007781static void
7782xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
7783 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007784 CHECK_ERROR;
7785 SKIP_BLANKS;
7786 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007787 int eq;
7788 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007789
7790 if (CUR == '=') eq = 1;
7791 else eq = 0;
7792 NEXT;
7793 if (!eq) NEXT;
7794 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007795 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007796 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007797 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007798 SKIP_BLANKS;
7799 }
7800}
7801
7802/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007803 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007804 * @ctxt: the XPath Parser context
7805 *
7806 * [22] AndExpr ::= EqualityExpr
7807 * | AndExpr 'and' EqualityExpr
7808 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007809 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007810 *
7811 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007812static void
7813xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
7814 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007815 CHECK_ERROR;
7816 SKIP_BLANKS;
7817 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007818 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007819 SKIP(3);
7820 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007821 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007822 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007823 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007824 SKIP_BLANKS;
7825 }
7826}
7827
7828/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007829 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007830 * @ctxt: the XPath Parser context
7831 *
7832 * [14] Expr ::= OrExpr
7833 * [21] OrExpr ::= AndExpr
7834 * | OrExpr 'or' AndExpr
7835 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007836 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00007837 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007838static void
7839xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
7840 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007841 CHECK_ERROR;
7842 SKIP_BLANKS;
7843 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007844 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007845 SKIP(2);
7846 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007847 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007848 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007849 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
7850 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00007851 SKIP_BLANKS;
7852 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007853 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
7854 /* more ops could be optimized too */
7855 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
7856 }
Owen Taylor3473f882001-02-23 17:55:21 +00007857}
7858
7859/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007860 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00007861 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007862 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00007863 *
7864 * [8] Predicate ::= '[' PredicateExpr ']'
7865 * [9] PredicateExpr ::= Expr
7866 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007867 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00007868 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007869static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007870xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007871 int op1 = ctxt->comp->last;
7872
7873 SKIP_BLANKS;
7874 if (CUR != '[') {
7875 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7876 }
7877 NEXT;
7878 SKIP_BLANKS;
7879
7880 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007881 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007882 CHECK_ERROR;
7883
7884 if (CUR != ']') {
7885 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7886 }
7887
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007888 if (filter)
7889 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
7890 else
7891 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007892
7893 NEXT;
7894 SKIP_BLANKS;
7895}
7896
7897/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007898 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00007899 * @ctxt: the XPath Parser context
7900 * @test: pointer to a xmlXPathTestVal
7901 * @type: pointer to a xmlXPathTypeVal
7902 * @prefix: placeholder for a possible name prefix
7903 *
7904 * [7] NodeTest ::= NameTest
7905 * | NodeType '(' ')'
7906 * | 'processing-instruction' '(' Literal ')'
7907 *
7908 * [37] NameTest ::= '*'
7909 * | NCName ':' '*'
7910 * | QName
7911 * [38] NodeType ::= 'comment'
7912 * | 'text'
7913 * | 'processing-instruction'
7914 * | 'node'
7915 *
7916 * Returns the name found and update @test, @type and @prefix appropriately
7917 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007918static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007919xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
7920 xmlXPathTypeVal *type, const xmlChar **prefix,
7921 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00007922 int blanks;
7923
7924 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
7925 STRANGE;
7926 return(NULL);
7927 }
7928 *type = 0;
7929 *test = 0;
7930 *prefix = NULL;
7931 SKIP_BLANKS;
7932
7933 if ((name == NULL) && (CUR == '*')) {
7934 /*
7935 * All elements
7936 */
7937 NEXT;
7938 *test = NODE_TEST_ALL;
7939 return(NULL);
7940 }
7941
7942 if (name == NULL)
7943 name = xmlXPathParseNCName(ctxt);
7944 if (name == NULL) {
7945 XP_ERROR0(XPATH_EXPR_ERROR);
7946 }
7947
7948 blanks = IS_BLANK(CUR);
7949 SKIP_BLANKS;
7950 if (CUR == '(') {
7951 NEXT;
7952 /*
7953 * NodeType or PI search
7954 */
7955 if (xmlStrEqual(name, BAD_CAST "comment"))
7956 *type = NODE_TYPE_COMMENT;
7957 else if (xmlStrEqual(name, BAD_CAST "node"))
7958 *type = NODE_TYPE_NODE;
7959 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
7960 *type = NODE_TYPE_PI;
7961 else if (xmlStrEqual(name, BAD_CAST "text"))
7962 *type = NODE_TYPE_TEXT;
7963 else {
7964 if (name != NULL)
7965 xmlFree(name);
7966 XP_ERROR0(XPATH_EXPR_ERROR);
7967 }
7968
7969 *test = NODE_TEST_TYPE;
7970
7971 SKIP_BLANKS;
7972 if (*type == NODE_TYPE_PI) {
7973 /*
7974 * Specific case: search a PI by name.
7975 */
Owen Taylor3473f882001-02-23 17:55:21 +00007976 if (name != NULL)
7977 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00007978 name = NULL;
7979 if (CUR != ')') {
7980 name = xmlXPathParseLiteral(ctxt);
7981 CHECK_ERROR 0;
7982 SKIP_BLANKS;
7983 }
Owen Taylor3473f882001-02-23 17:55:21 +00007984 }
7985 if (CUR != ')') {
7986 if (name != NULL)
7987 xmlFree(name);
7988 XP_ERROR0(XPATH_UNCLOSED_ERROR);
7989 }
7990 NEXT;
7991 return(name);
7992 }
7993 *test = NODE_TEST_NAME;
7994 if ((!blanks) && (CUR == ':')) {
7995 NEXT;
7996
7997 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007998 * Since currently the parser context don't have a
7999 * namespace list associated:
8000 * The namespace name for this prefix can be computed
8001 * only at evaluation time. The compilation is done
8002 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008003 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008004#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008005 *prefix = xmlXPathNsLookup(ctxt->context, name);
8006 if (name != NULL)
8007 xmlFree(name);
8008 if (*prefix == NULL) {
8009 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8010 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008011#else
8012 *prefix = name;
8013#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008014
8015 if (CUR == '*') {
8016 /*
8017 * All elements
8018 */
8019 NEXT;
8020 *test = NODE_TEST_ALL;
8021 return(NULL);
8022 }
8023
8024 name = xmlXPathParseNCName(ctxt);
8025 if (name == NULL) {
8026 XP_ERROR0(XPATH_EXPR_ERROR);
8027 }
8028 }
8029 return(name);
8030}
8031
8032/**
8033 * xmlXPathIsAxisName:
8034 * @name: a preparsed name token
8035 *
8036 * [6] AxisName ::= 'ancestor'
8037 * | 'ancestor-or-self'
8038 * | 'attribute'
8039 * | 'child'
8040 * | 'descendant'
8041 * | 'descendant-or-self'
8042 * | 'following'
8043 * | 'following-sibling'
8044 * | 'namespace'
8045 * | 'parent'
8046 * | 'preceding'
8047 * | 'preceding-sibling'
8048 * | 'self'
8049 *
8050 * Returns the axis or 0
8051 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008052static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008053xmlXPathIsAxisName(const xmlChar *name) {
8054 xmlXPathAxisVal ret = 0;
8055 switch (name[0]) {
8056 case 'a':
8057 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8058 ret = AXIS_ANCESTOR;
8059 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8060 ret = AXIS_ANCESTOR_OR_SELF;
8061 if (xmlStrEqual(name, BAD_CAST "attribute"))
8062 ret = AXIS_ATTRIBUTE;
8063 break;
8064 case 'c':
8065 if (xmlStrEqual(name, BAD_CAST "child"))
8066 ret = AXIS_CHILD;
8067 break;
8068 case 'd':
8069 if (xmlStrEqual(name, BAD_CAST "descendant"))
8070 ret = AXIS_DESCENDANT;
8071 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8072 ret = AXIS_DESCENDANT_OR_SELF;
8073 break;
8074 case 'f':
8075 if (xmlStrEqual(name, BAD_CAST "following"))
8076 ret = AXIS_FOLLOWING;
8077 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8078 ret = AXIS_FOLLOWING_SIBLING;
8079 break;
8080 case 'n':
8081 if (xmlStrEqual(name, BAD_CAST "namespace"))
8082 ret = AXIS_NAMESPACE;
8083 break;
8084 case 'p':
8085 if (xmlStrEqual(name, BAD_CAST "parent"))
8086 ret = AXIS_PARENT;
8087 if (xmlStrEqual(name, BAD_CAST "preceding"))
8088 ret = AXIS_PRECEDING;
8089 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8090 ret = AXIS_PRECEDING_SIBLING;
8091 break;
8092 case 's':
8093 if (xmlStrEqual(name, BAD_CAST "self"))
8094 ret = AXIS_SELF;
8095 break;
8096 }
8097 return(ret);
8098}
8099
8100/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008101 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008102 * @ctxt: the XPath Parser context
8103 *
8104 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8105 * | AbbreviatedStep
8106 *
8107 * [12] AbbreviatedStep ::= '.' | '..'
8108 *
8109 * [5] AxisSpecifier ::= AxisName '::'
8110 * | AbbreviatedAxisSpecifier
8111 *
8112 * [13] AbbreviatedAxisSpecifier ::= '@'?
8113 *
8114 * Modified for XPtr range support as:
8115 *
8116 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8117 * | AbbreviatedStep
8118 * | 'range-to' '(' Expr ')' Predicate*
8119 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008120 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008121 * A location step of . is short for self::node(). This is
8122 * particularly useful in conjunction with //. For example, the
8123 * location path .//para is short for
8124 * self::node()/descendant-or-self::node()/child::para
8125 * and so will select all para descendant elements of the context
8126 * node.
8127 * Similarly, a location step of .. is short for parent::node().
8128 * For example, ../title is short for parent::node()/child::title
8129 * and so will select the title children of the parent of the context
8130 * node.
8131 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008132static void
8133xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008134#ifdef LIBXML_XPTR_ENABLED
8135 int rangeto = 0;
8136 int op2 = -1;
8137#endif
8138
Owen Taylor3473f882001-02-23 17:55:21 +00008139 SKIP_BLANKS;
8140 if ((CUR == '.') && (NXT(1) == '.')) {
8141 SKIP(2);
8142 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008143 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8144 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008145 } else if (CUR == '.') {
8146 NEXT;
8147 SKIP_BLANKS;
8148 } else {
8149 xmlChar *name = NULL;
8150 const xmlChar *prefix = NULL;
8151 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008152 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008153 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008154 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008155
8156 /*
8157 * The modification needed for XPointer change to the production
8158 */
8159#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008160 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008161 name = xmlXPathParseNCName(ctxt);
8162 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008163 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008164 xmlFree(name);
8165 SKIP_BLANKS;
8166 if (CUR != '(') {
8167 XP_ERROR(XPATH_EXPR_ERROR);
8168 }
8169 NEXT;
8170 SKIP_BLANKS;
8171
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008172 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008173 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008174 CHECK_ERROR;
8175
8176 SKIP_BLANKS;
8177 if (CUR != ')') {
8178 XP_ERROR(XPATH_EXPR_ERROR);
8179 }
8180 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008181 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008182 goto eval_predicates;
8183 }
8184 }
8185#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008186 if (CUR == '*') {
8187 axis = AXIS_CHILD;
8188 } else {
8189 if (name == NULL)
8190 name = xmlXPathParseNCName(ctxt);
8191 if (name != NULL) {
8192 axis = xmlXPathIsAxisName(name);
8193 if (axis != 0) {
8194 SKIP_BLANKS;
8195 if ((CUR == ':') && (NXT(1) == ':')) {
8196 SKIP(2);
8197 xmlFree(name);
8198 name = NULL;
8199 } else {
8200 /* an element name can conflict with an axis one :-\ */
8201 axis = AXIS_CHILD;
8202 }
Owen Taylor3473f882001-02-23 17:55:21 +00008203 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008204 axis = AXIS_CHILD;
8205 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008206 } else if (CUR == '@') {
8207 NEXT;
8208 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008209 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008210 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008211 }
Owen Taylor3473f882001-02-23 17:55:21 +00008212 }
8213
8214 CHECK_ERROR;
8215
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008216 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008217 if (test == 0)
8218 return;
8219
8220#ifdef DEBUG_STEP
8221 xmlGenericError(xmlGenericErrorContext,
8222 "Basis : computing new set\n");
8223#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008224
Owen Taylor3473f882001-02-23 17:55:21 +00008225#ifdef DEBUG_STEP
8226 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008227 if (ctxt->value == NULL)
8228 xmlGenericError(xmlGenericErrorContext, "no value\n");
8229 else if (ctxt->value->nodesetval == NULL)
8230 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8231 else
8232 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008233#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008234
8235eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008236 op1 = ctxt->comp->last;
8237 ctxt->comp->last = -1;
8238
Owen Taylor3473f882001-02-23 17:55:21 +00008239 SKIP_BLANKS;
8240 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008241 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008242 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008243
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008244#ifdef LIBXML_XPTR_ENABLED
8245 if (rangeto) {
8246 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8247 } else
8248#endif
8249 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8250 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008251
Owen Taylor3473f882001-02-23 17:55:21 +00008252 }
8253#ifdef DEBUG_STEP
8254 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008255 if (ctxt->value == NULL)
8256 xmlGenericError(xmlGenericErrorContext, "no value\n");
8257 else if (ctxt->value->nodesetval == NULL)
8258 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8259 else
8260 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8261 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008262#endif
8263}
8264
8265/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008266 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008267 * @ctxt: the XPath Parser context
8268 *
8269 * [3] RelativeLocationPath ::= Step
8270 * | RelativeLocationPath '/' Step
8271 * | AbbreviatedRelativeLocationPath
8272 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8273 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008274 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008275 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008276static void
Owen Taylor3473f882001-02-23 17:55:21 +00008277#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008278xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008279#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008280xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008281#endif
8282(xmlXPathParserContextPtr ctxt) {
8283 SKIP_BLANKS;
8284 if ((CUR == '/') && (NXT(1) == '/')) {
8285 SKIP(2);
8286 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008287 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8288 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008289 } else if (CUR == '/') {
8290 NEXT;
8291 SKIP_BLANKS;
8292 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008293 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008294 SKIP_BLANKS;
8295 while (CUR == '/') {
8296 if ((CUR == '/') && (NXT(1) == '/')) {
8297 SKIP(2);
8298 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008299 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008300 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008301 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008302 } else if (CUR == '/') {
8303 NEXT;
8304 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008305 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008306 }
8307 SKIP_BLANKS;
8308 }
8309}
8310
8311/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008312 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008313 * @ctxt: the XPath Parser context
8314 *
8315 * [1] LocationPath ::= RelativeLocationPath
8316 * | AbsoluteLocationPath
8317 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8318 * | AbbreviatedAbsoluteLocationPath
8319 * [10] AbbreviatedAbsoluteLocationPath ::=
8320 * '//' RelativeLocationPath
8321 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008322 * Compile a location path
8323 *
Owen Taylor3473f882001-02-23 17:55:21 +00008324 * // is short for /descendant-or-self::node()/. For example,
8325 * //para is short for /descendant-or-self::node()/child::para and
8326 * so will select any para element in the document (even a para element
8327 * that is a document element will be selected by //para since the
8328 * document element node is a child of the root node); div//para is
8329 * short for div/descendant-or-self::node()/child::para and so will
8330 * select all para descendants of div children.
8331 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008332static void
8333xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008334 SKIP_BLANKS;
8335 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008336 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008337 } else {
8338 while (CUR == '/') {
8339 if ((CUR == '/') && (NXT(1) == '/')) {
8340 SKIP(2);
8341 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008342 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8343 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008344 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008345 } else if (CUR == '/') {
8346 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008347 SKIP_BLANKS;
8348 if ((CUR != 0 ) &&
8349 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
8350 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008351 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008352 }
8353 }
8354 }
8355}
8356
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008357/************************************************************************
8358 * *
8359 * XPath precompiled expression evaluation *
8360 * *
8361 ************************************************************************/
8362
Daniel Veillardf06307e2001-07-03 10:35:50 +00008363static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008364xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8365
8366/**
8367 * xmlXPathNodeCollectAndTest:
8368 * @ctxt: the XPath Parser context
8369 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008370 * @first: pointer to the first element in document order
8371 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008372 *
8373 * This is the function implementing a step: based on the current list
8374 * of nodes, it builds up a new list, looking at all nodes under that
8375 * axis and selecting them it also do the predicate filtering
8376 *
8377 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00008378 *
8379 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008380 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008381static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008382xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008383 xmlXPathStepOpPtr op,
8384 xmlNodePtr * first, xmlNodePtr * last)
8385{
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008386 xmlXPathAxisVal axis = op->value;
8387 xmlXPathTestVal test = op->value2;
8388 xmlXPathTypeVal type = op->value3;
8389 const xmlChar *prefix = op->value4;
8390 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008391 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008392
8393#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008394 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008395#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008396 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008397 xmlNodeSetPtr ret, list;
8398 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008399 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00008400 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008401 xmlNodePtr cur = NULL;
8402 xmlXPathObjectPtr obj;
8403 xmlNodeSetPtr nodelist;
8404 xmlNodePtr tmp;
8405
Daniel Veillardf06307e2001-07-03 10:35:50 +00008406 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008407 obj = valuePop(ctxt);
8408 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00008409 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008410 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008411 URI = xmlXPathNsLookup(ctxt->context, prefix);
8412 if (URI == NULL)
8413 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008414 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008415#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008416 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008417#endif
8418 switch (axis) {
8419 case AXIS_ANCESTOR:
8420#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008421 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008422#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008423 first = NULL;
8424 next = xmlXPathNextAncestor;
8425 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008426 case AXIS_ANCESTOR_OR_SELF:
8427#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008428 xmlGenericError(xmlGenericErrorContext,
8429 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008430#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008431 first = NULL;
8432 next = xmlXPathNextAncestorOrSelf;
8433 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008434 case AXIS_ATTRIBUTE:
8435#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008436 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008437#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008438 first = NULL;
8439 last = NULL;
8440 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00008441 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008442 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008443 case AXIS_CHILD:
8444#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008445 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008446#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008447 last = NULL;
8448 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00008449 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008450 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008451 case AXIS_DESCENDANT:
8452#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008453 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008454#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008455 last = NULL;
8456 next = xmlXPathNextDescendant;
8457 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008458 case AXIS_DESCENDANT_OR_SELF:
8459#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008460 xmlGenericError(xmlGenericErrorContext,
8461 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008462#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008463 last = NULL;
8464 next = xmlXPathNextDescendantOrSelf;
8465 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008466 case AXIS_FOLLOWING:
8467#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008468 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008469#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008470 last = NULL;
8471 next = xmlXPathNextFollowing;
8472 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008473 case AXIS_FOLLOWING_SIBLING:
8474#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008475 xmlGenericError(xmlGenericErrorContext,
8476 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008477#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008478 last = NULL;
8479 next = xmlXPathNextFollowingSibling;
8480 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008481 case AXIS_NAMESPACE:
8482#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008483 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008484#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008485 first = NULL;
8486 last = NULL;
8487 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00008488 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008489 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008490 case AXIS_PARENT:
8491#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008492 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008493#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008494 first = NULL;
8495 next = xmlXPathNextParent;
8496 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008497 case AXIS_PRECEDING:
8498#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008499 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008500#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008501 first = NULL;
8502 next = xmlXPathNextPrecedingInternal;
8503 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008504 case AXIS_PRECEDING_SIBLING:
8505#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008506 xmlGenericError(xmlGenericErrorContext,
8507 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008508#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008509 first = NULL;
8510 next = xmlXPathNextPrecedingSibling;
8511 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008512 case AXIS_SELF:
8513#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008514 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008515#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008516 first = NULL;
8517 last = NULL;
8518 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00008519 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008520 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008521 }
8522 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008523 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008524
8525 nodelist = obj->nodesetval;
8526 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008527 xmlXPathFreeObject(obj);
8528 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8529 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008530 }
8531 addNode = xmlXPathNodeSetAddUnique;
8532 ret = NULL;
8533#ifdef DEBUG_STEP
8534 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008535 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008536 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008537 case NODE_TEST_NONE:
8538 xmlGenericError(xmlGenericErrorContext,
8539 " searching for none !!!\n");
8540 break;
8541 case NODE_TEST_TYPE:
8542 xmlGenericError(xmlGenericErrorContext,
8543 " searching for type %d\n", type);
8544 break;
8545 case NODE_TEST_PI:
8546 xmlGenericError(xmlGenericErrorContext,
8547 " searching for PI !!!\n");
8548 break;
8549 case NODE_TEST_ALL:
8550 xmlGenericError(xmlGenericErrorContext,
8551 " searching for *\n");
8552 break;
8553 case NODE_TEST_NS:
8554 xmlGenericError(xmlGenericErrorContext,
8555 " searching for namespace %s\n",
8556 prefix);
8557 break;
8558 case NODE_TEST_NAME:
8559 xmlGenericError(xmlGenericErrorContext,
8560 " searching for name %s\n", name);
8561 if (prefix != NULL)
8562 xmlGenericError(xmlGenericErrorContext,
8563 " with namespace %s\n", prefix);
8564 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008565 }
8566 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8567#endif
8568 /*
8569 * 2.3 Node Tests
8570 * - For the attribute axis, the principal node type is attribute.
8571 * - For the namespace axis, the principal node type is namespace.
8572 * - For other axes, the principal node type is element.
8573 *
8574 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008575 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008576 * select all element children of the context node
8577 */
8578 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008579 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008580 ctxt->context->node = nodelist->nodeTab[i];
8581
Daniel Veillardf06307e2001-07-03 10:35:50 +00008582 cur = NULL;
8583 list = xmlXPathNodeSetCreate(NULL);
8584 do {
8585 cur = next(ctxt, cur);
8586 if (cur == NULL)
8587 break;
8588 if ((first != NULL) && (*first == cur))
8589 break;
8590 if (((t % 256) == 0) &&
8591 (first != NULL) && (*first != NULL) &&
8592 (xmlXPathCmpNodes(*first, cur) >= 0))
8593 break;
8594 if ((last != NULL) && (*last == cur))
8595 break;
8596 if (((t % 256) == 0) &&
8597 (last != NULL) && (*last != NULL) &&
8598 (xmlXPathCmpNodes(cur, *last) >= 0))
8599 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008600 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008601#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008602 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
8603#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008604 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008605 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008606 ctxt->context->node = tmp;
8607 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008608 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008609 if ((cur->type == type) ||
8610 ((type == NODE_TYPE_NODE) &&
8611 ((cur->type == XML_DOCUMENT_NODE) ||
8612 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8613 (cur->type == XML_ELEMENT_NODE) ||
8614 (cur->type == XML_PI_NODE) ||
8615 (cur->type == XML_COMMENT_NODE) ||
8616 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00008617 (cur->type == XML_TEXT_NODE))) ||
8618 ((type == NODE_TYPE_TEXT) &&
8619 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008620#ifdef DEBUG_STEP
8621 n++;
8622#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008623 addNode(list, cur);
8624 }
8625 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008626 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008627 if (cur->type == XML_PI_NODE) {
8628 if ((name != NULL) &&
8629 (!xmlStrEqual(name, cur->name)))
8630 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008631#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008632 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008633#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008634 addNode(list, cur);
8635 }
8636 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008637 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008638 if (axis == AXIS_ATTRIBUTE) {
8639 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008640#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008641 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008642#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008643 addNode(list, cur);
8644 }
8645 } else if (axis == AXIS_NAMESPACE) {
8646 if (cur->type == XML_NAMESPACE_DECL) {
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 Veillard044fc6b2002-03-04 17:09:44 +00008650 xmlXPathNodeSetAddNs(list, ctxt->context->node,
8651 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008652 }
8653 } else {
8654 if (cur->type == XML_ELEMENT_NODE) {
8655 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008656#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008657 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008658#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008659 addNode(list, cur);
8660 } else if ((cur->ns != NULL) &&
8661 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008662#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008663 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008664#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008665 addNode(list, cur);
8666 }
8667 }
8668 }
8669 break;
8670 case NODE_TEST_NS:{
8671 TODO;
8672 break;
8673 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008674 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008675 switch (cur->type) {
8676 case XML_ELEMENT_NODE:
8677 if (xmlStrEqual(name, cur->name)) {
8678 if (prefix == NULL) {
8679 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008680#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008681 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008682#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008683 addNode(list, cur);
8684 }
8685 } else {
8686 if ((cur->ns != NULL) &&
8687 (xmlStrEqual(URI,
8688 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008689#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008690 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008691#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008692 addNode(list, cur);
8693 }
8694 }
8695 }
8696 break;
8697 case XML_ATTRIBUTE_NODE:{
8698 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008699
Daniel Veillardf06307e2001-07-03 10:35:50 +00008700 if (xmlStrEqual(name, attr->name)) {
8701 if (prefix == NULL) {
8702 if ((attr->ns == NULL) ||
8703 (attr->ns->prefix == NULL)) {
8704#ifdef DEBUG_STEP
8705 n++;
8706#endif
8707 addNode(list,
8708 (xmlNodePtr) attr);
8709 }
8710 } else {
8711 if ((attr->ns != NULL) &&
8712 (xmlStrEqual(URI,
8713 attr->ns->
8714 href))) {
8715#ifdef DEBUG_STEP
8716 n++;
8717#endif
8718 addNode(list,
8719 (xmlNodePtr) attr);
8720 }
8721 }
8722 }
8723 break;
8724 }
8725 case XML_NAMESPACE_DECL:
8726 if (cur->type == XML_NAMESPACE_DECL) {
8727 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008728
Daniel Veillardf06307e2001-07-03 10:35:50 +00008729 if ((ns->prefix != NULL) && (name != NULL)
8730 && (xmlStrEqual(ns->prefix, name))) {
8731#ifdef DEBUG_STEP
8732 n++;
8733#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008734 xmlXPathNodeSetAddNs(list,
8735 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008736 }
8737 }
8738 break;
8739 default:
8740 break;
8741 }
8742 break;
8743 break;
8744 }
8745 } while (cur != NULL);
8746
8747 /*
8748 * If there is some predicate filtering do it now
8749 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00008750 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008751 xmlXPathObjectPtr obj2;
8752
8753 valuePush(ctxt, xmlXPathWrapNodeSet(list));
8754 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
8755 CHECK_TYPE0(XPATH_NODESET);
8756 obj2 = valuePop(ctxt);
8757 list = obj2->nodesetval;
8758 obj2->nodesetval = NULL;
8759 xmlXPathFreeObject(obj2);
8760 }
8761 if (ret == NULL) {
8762 ret = list;
8763 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00008764 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008765 xmlXPathFreeNodeSet(list);
8766 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008767 }
8768 ctxt->context->node = tmp;
8769#ifdef DEBUG_STEP
8770 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008771 "\nExamined %d nodes, found %d nodes at that step\n",
8772 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008773#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008774 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00008775 if ((obj->boolval) && (obj->user != NULL)) {
8776 ctxt->value->boolval = 1;
8777 ctxt->value->user = obj->user;
8778 obj->user = NULL;
8779 obj->boolval = 0;
8780 }
8781 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008782 return(t);
8783}
8784
8785/**
8786 * xmlXPathNodeCollectAndTestNth:
8787 * @ctxt: the XPath Parser context
8788 * @op: the XPath precompiled step operation
8789 * @indx: the index to collect
8790 * @first: pointer to the first element in document order
8791 * @last: pointer to the last element in document order
8792 *
8793 * This is the function implementing a step: based on the current list
8794 * of nodes, it builds up a new list, looking at all nodes under that
8795 * axis and selecting them it also do the predicate filtering
8796 *
8797 * Pushes the new NodeSet resulting from the search.
8798 * Returns the number of node traversed
8799 */
8800static int
8801xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
8802 xmlXPathStepOpPtr op, int indx,
8803 xmlNodePtr * first, xmlNodePtr * last)
8804{
8805 xmlXPathAxisVal axis = op->value;
8806 xmlXPathTestVal test = op->value2;
8807 xmlXPathTypeVal type = op->value3;
8808 const xmlChar *prefix = op->value4;
8809 const xmlChar *name = op->value5;
8810 const xmlChar *URI = NULL;
8811 int n = 0, t = 0;
8812
8813 int i;
8814 xmlNodeSetPtr list;
8815 xmlXPathTraversalFunction next = NULL;
8816 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
8817 xmlNodePtr cur = NULL;
8818 xmlXPathObjectPtr obj;
8819 xmlNodeSetPtr nodelist;
8820 xmlNodePtr tmp;
8821
8822 CHECK_TYPE0(XPATH_NODESET);
8823 obj = valuePop(ctxt);
8824 addNode = xmlXPathNodeSetAdd;
8825 if (prefix != NULL) {
8826 URI = xmlXPathNsLookup(ctxt->context, prefix);
8827 if (URI == NULL)
8828 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8829 }
8830#ifdef DEBUG_STEP_NTH
8831 xmlGenericError(xmlGenericErrorContext, "new step : ");
8832 if (first != NULL) {
8833 if (*first != NULL)
8834 xmlGenericError(xmlGenericErrorContext, "first = %s ",
8835 (*first)->name);
8836 else
8837 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
8838 }
8839 if (last != NULL) {
8840 if (*last != NULL)
8841 xmlGenericError(xmlGenericErrorContext, "last = %s ",
8842 (*last)->name);
8843 else
8844 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
8845 }
8846#endif
8847 switch (axis) {
8848 case AXIS_ANCESTOR:
8849#ifdef DEBUG_STEP_NTH
8850 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
8851#endif
8852 first = NULL;
8853 next = xmlXPathNextAncestor;
8854 break;
8855 case AXIS_ANCESTOR_OR_SELF:
8856#ifdef DEBUG_STEP_NTH
8857 xmlGenericError(xmlGenericErrorContext,
8858 "axis 'ancestors-or-self' ");
8859#endif
8860 first = NULL;
8861 next = xmlXPathNextAncestorOrSelf;
8862 break;
8863 case AXIS_ATTRIBUTE:
8864#ifdef DEBUG_STEP_NTH
8865 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
8866#endif
8867 first = NULL;
8868 last = NULL;
8869 next = xmlXPathNextAttribute;
8870 break;
8871 case AXIS_CHILD:
8872#ifdef DEBUG_STEP_NTH
8873 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
8874#endif
8875 last = NULL;
8876 next = xmlXPathNextChild;
8877 break;
8878 case AXIS_DESCENDANT:
8879#ifdef DEBUG_STEP_NTH
8880 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
8881#endif
8882 last = NULL;
8883 next = xmlXPathNextDescendant;
8884 break;
8885 case AXIS_DESCENDANT_OR_SELF:
8886#ifdef DEBUG_STEP_NTH
8887 xmlGenericError(xmlGenericErrorContext,
8888 "axis 'descendant-or-self' ");
8889#endif
8890 last = NULL;
8891 next = xmlXPathNextDescendantOrSelf;
8892 break;
8893 case AXIS_FOLLOWING:
8894#ifdef DEBUG_STEP_NTH
8895 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
8896#endif
8897 last = NULL;
8898 next = xmlXPathNextFollowing;
8899 break;
8900 case AXIS_FOLLOWING_SIBLING:
8901#ifdef DEBUG_STEP_NTH
8902 xmlGenericError(xmlGenericErrorContext,
8903 "axis 'following-siblings' ");
8904#endif
8905 last = NULL;
8906 next = xmlXPathNextFollowingSibling;
8907 break;
8908 case AXIS_NAMESPACE:
8909#ifdef DEBUG_STEP_NTH
8910 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
8911#endif
8912 last = NULL;
8913 first = NULL;
8914 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
8915 break;
8916 case AXIS_PARENT:
8917#ifdef DEBUG_STEP_NTH
8918 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
8919#endif
8920 first = NULL;
8921 next = xmlXPathNextParent;
8922 break;
8923 case AXIS_PRECEDING:
8924#ifdef DEBUG_STEP_NTH
8925 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
8926#endif
8927 first = NULL;
8928 next = xmlXPathNextPrecedingInternal;
8929 break;
8930 case AXIS_PRECEDING_SIBLING:
8931#ifdef DEBUG_STEP_NTH
8932 xmlGenericError(xmlGenericErrorContext,
8933 "axis 'preceding-sibling' ");
8934#endif
8935 first = NULL;
8936 next = xmlXPathNextPrecedingSibling;
8937 break;
8938 case AXIS_SELF:
8939#ifdef DEBUG_STEP_NTH
8940 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
8941#endif
8942 first = NULL;
8943 last = NULL;
8944 next = xmlXPathNextSelf;
8945 break;
8946 }
8947 if (next == NULL)
8948 return(0);
8949
8950 nodelist = obj->nodesetval;
8951 if (nodelist == NULL) {
8952 xmlXPathFreeObject(obj);
8953 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8954 return(0);
8955 }
8956 addNode = xmlXPathNodeSetAddUnique;
8957#ifdef DEBUG_STEP_NTH
8958 xmlGenericError(xmlGenericErrorContext,
8959 " context contains %d nodes\n", nodelist->nodeNr);
8960 switch (test) {
8961 case NODE_TEST_NONE:
8962 xmlGenericError(xmlGenericErrorContext,
8963 " searching for none !!!\n");
8964 break;
8965 case NODE_TEST_TYPE:
8966 xmlGenericError(xmlGenericErrorContext,
8967 " searching for type %d\n", type);
8968 break;
8969 case NODE_TEST_PI:
8970 xmlGenericError(xmlGenericErrorContext,
8971 " searching for PI !!!\n");
8972 break;
8973 case NODE_TEST_ALL:
8974 xmlGenericError(xmlGenericErrorContext,
8975 " searching for *\n");
8976 break;
8977 case NODE_TEST_NS:
8978 xmlGenericError(xmlGenericErrorContext,
8979 " searching for namespace %s\n",
8980 prefix);
8981 break;
8982 case NODE_TEST_NAME:
8983 xmlGenericError(xmlGenericErrorContext,
8984 " searching for name %s\n", name);
8985 if (prefix != NULL)
8986 xmlGenericError(xmlGenericErrorContext,
8987 " with namespace %s\n", prefix);
8988 break;
8989 }
8990 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8991#endif
8992 /*
8993 * 2.3 Node Tests
8994 * - For the attribute axis, the principal node type is attribute.
8995 * - For the namespace axis, the principal node type is namespace.
8996 * - For other axes, the principal node type is element.
8997 *
8998 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008999 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009000 * select all element children of the context node
9001 */
9002 tmp = ctxt->context->node;
9003 list = xmlXPathNodeSetCreate(NULL);
9004 for (i = 0; i < nodelist->nodeNr; i++) {
9005 ctxt->context->node = nodelist->nodeTab[i];
9006
9007 cur = NULL;
9008 n = 0;
9009 do {
9010 cur = next(ctxt, cur);
9011 if (cur == NULL)
9012 break;
9013 if ((first != NULL) && (*first == cur))
9014 break;
9015 if (((t % 256) == 0) &&
9016 (first != NULL) && (*first != NULL) &&
9017 (xmlXPathCmpNodes(*first, cur) >= 0))
9018 break;
9019 if ((last != NULL) && (*last == cur))
9020 break;
9021 if (((t % 256) == 0) &&
9022 (last != NULL) && (*last != NULL) &&
9023 (xmlXPathCmpNodes(cur, *last) >= 0))
9024 break;
9025 t++;
9026 switch (test) {
9027 case NODE_TEST_NONE:
9028 ctxt->context->node = tmp;
9029 STRANGE return(0);
9030 case NODE_TEST_TYPE:
9031 if ((cur->type == type) ||
9032 ((type == NODE_TYPE_NODE) &&
9033 ((cur->type == XML_DOCUMENT_NODE) ||
9034 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9035 (cur->type == XML_ELEMENT_NODE) ||
9036 (cur->type == XML_PI_NODE) ||
9037 (cur->type == XML_COMMENT_NODE) ||
9038 (cur->type == XML_CDATA_SECTION_NODE) ||
9039 (cur->type == XML_TEXT_NODE)))) {
9040 n++;
9041 if (n == indx)
9042 addNode(list, cur);
9043 }
9044 break;
9045 case NODE_TEST_PI:
9046 if (cur->type == XML_PI_NODE) {
9047 if ((name != NULL) &&
9048 (!xmlStrEqual(name, cur->name)))
9049 break;
9050 n++;
9051 if (n == indx)
9052 addNode(list, cur);
9053 }
9054 break;
9055 case NODE_TEST_ALL:
9056 if (axis == AXIS_ATTRIBUTE) {
9057 if (cur->type == XML_ATTRIBUTE_NODE) {
9058 n++;
9059 if (n == indx)
9060 addNode(list, cur);
9061 }
9062 } else if (axis == AXIS_NAMESPACE) {
9063 if (cur->type == XML_NAMESPACE_DECL) {
9064 n++;
9065 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009066 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9067 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009068 }
9069 } else {
9070 if (cur->type == XML_ELEMENT_NODE) {
9071 if (prefix == NULL) {
9072 n++;
9073 if (n == indx)
9074 addNode(list, cur);
9075 } else if ((cur->ns != NULL) &&
9076 (xmlStrEqual(URI, cur->ns->href))) {
9077 n++;
9078 if (n == indx)
9079 addNode(list, cur);
9080 }
9081 }
9082 }
9083 break;
9084 case NODE_TEST_NS:{
9085 TODO;
9086 break;
9087 }
9088 case NODE_TEST_NAME:
9089 switch (cur->type) {
9090 case XML_ELEMENT_NODE:
9091 if (xmlStrEqual(name, cur->name)) {
9092 if (prefix == NULL) {
9093 if (cur->ns == NULL) {
9094 n++;
9095 if (n == indx)
9096 addNode(list, cur);
9097 }
9098 } else {
9099 if ((cur->ns != NULL) &&
9100 (xmlStrEqual(URI,
9101 cur->ns->href))) {
9102 n++;
9103 if (n == indx)
9104 addNode(list, cur);
9105 }
9106 }
9107 }
9108 break;
9109 case XML_ATTRIBUTE_NODE:{
9110 xmlAttrPtr attr = (xmlAttrPtr) cur;
9111
9112 if (xmlStrEqual(name, attr->name)) {
9113 if (prefix == NULL) {
9114 if ((attr->ns == NULL) ||
9115 (attr->ns->prefix == NULL)) {
9116 n++;
9117 if (n == indx)
9118 addNode(list, cur);
9119 }
9120 } else {
9121 if ((attr->ns != NULL) &&
9122 (xmlStrEqual(URI,
9123 attr->ns->
9124 href))) {
9125 n++;
9126 if (n == indx)
9127 addNode(list, cur);
9128 }
9129 }
9130 }
9131 break;
9132 }
9133 case XML_NAMESPACE_DECL:
9134 if (cur->type == XML_NAMESPACE_DECL) {
9135 xmlNsPtr ns = (xmlNsPtr) cur;
9136
9137 if ((ns->prefix != NULL) && (name != NULL)
9138 && (xmlStrEqual(ns->prefix, name))) {
9139 n++;
9140 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009141 xmlXPathNodeSetAddNs(list,
9142 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009143 }
9144 }
9145 break;
9146 default:
9147 break;
9148 }
9149 break;
9150 break;
9151 }
9152 } while (n < indx);
9153 }
9154 ctxt->context->node = tmp;
9155#ifdef DEBUG_STEP_NTH
9156 xmlGenericError(xmlGenericErrorContext,
9157 "\nExamined %d nodes, found %d nodes at that step\n",
9158 t, list->nodeNr);
9159#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009160 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009161 if ((obj->boolval) && (obj->user != NULL)) {
9162 ctxt->value->boolval = 1;
9163 ctxt->value->user = obj->user;
9164 obj->user = NULL;
9165 obj->boolval = 0;
9166 }
9167 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009168 return(t);
9169}
9170
9171/**
9172 * xmlXPathCompOpEvalFirst:
9173 * @ctxt: the XPath parser context with the compiled expression
9174 * @op: an XPath compiled operation
9175 * @first: the first elem found so far
9176 *
9177 * Evaluate the Precompiled XPath operation searching only the first
9178 * element in document order
9179 *
9180 * Returns the number of examined objects.
9181 */
9182static int
9183xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9184 xmlXPathStepOpPtr op, xmlNodePtr * first)
9185{
9186 int total = 0, cur;
9187 xmlXPathCompExprPtr comp;
9188 xmlXPathObjectPtr arg1, arg2;
9189
Daniel Veillard556c6682001-10-06 09:59:51 +00009190 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009191 comp = ctxt->comp;
9192 switch (op->op) {
9193 case XPATH_OP_END:
9194 return (0);
9195 case XPATH_OP_UNION:
9196 total =
9197 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9198 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009199 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009200 if ((ctxt->value != NULL)
9201 && (ctxt->value->type == XPATH_NODESET)
9202 && (ctxt->value->nodesetval != NULL)
9203 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9204 /*
9205 * limit tree traversing to first node in the result
9206 */
9207 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9208 *first = ctxt->value->nodesetval->nodeTab[0];
9209 }
9210 cur =
9211 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9212 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009213 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009214 CHECK_TYPE0(XPATH_NODESET);
9215 arg2 = valuePop(ctxt);
9216
9217 CHECK_TYPE0(XPATH_NODESET);
9218 arg1 = valuePop(ctxt);
9219
9220 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9221 arg2->nodesetval);
9222 valuePush(ctxt, arg1);
9223 xmlXPathFreeObject(arg2);
9224 /* optimizer */
9225 if (total > cur)
9226 xmlXPathCompSwap(op);
9227 return (total + cur);
9228 case XPATH_OP_ROOT:
9229 xmlXPathRoot(ctxt);
9230 return (0);
9231 case XPATH_OP_NODE:
9232 if (op->ch1 != -1)
9233 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009234 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009235 if (op->ch2 != -1)
9236 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009237 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009238 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9239 return (total);
9240 case XPATH_OP_RESET:
9241 if (op->ch1 != -1)
9242 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009243 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009244 if (op->ch2 != -1)
9245 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009246 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009247 ctxt->context->node = NULL;
9248 return (total);
9249 case XPATH_OP_COLLECT:{
9250 if (op->ch1 == -1)
9251 return (total);
9252
9253 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009254 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009255
9256 /*
9257 * Optimization for [n] selection where n is a number
9258 */
9259 if ((op->ch2 != -1) &&
9260 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9261 (comp->steps[op->ch2].ch1 == -1) &&
9262 (comp->steps[op->ch2].ch2 != -1) &&
9263 (comp->steps[comp->steps[op->ch2].ch2].op ==
9264 XPATH_OP_VALUE)) {
9265 xmlXPathObjectPtr val;
9266
9267 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9268 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9269 int indx = (int) val->floatval;
9270
9271 if (val->floatval == (float) indx) {
9272 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9273 first, NULL);
9274 return (total);
9275 }
9276 }
9277 }
9278 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9279 return (total);
9280 }
9281 case XPATH_OP_VALUE:
9282 valuePush(ctxt,
9283 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9284 return (0);
9285 case XPATH_OP_SORT:
9286 if (op->ch1 != -1)
9287 total +=
9288 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9289 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009290 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009291 if ((ctxt->value != NULL)
9292 && (ctxt->value->type == XPATH_NODESET)
9293 && (ctxt->value->nodesetval != NULL))
9294 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9295 return (total);
9296 default:
9297 return (xmlXPathCompOpEval(ctxt, op));
9298 }
9299}
9300
9301/**
9302 * xmlXPathCompOpEvalLast:
9303 * @ctxt: the XPath parser context with the compiled expression
9304 * @op: an XPath compiled operation
9305 * @last: the last elem found so far
9306 *
9307 * Evaluate the Precompiled XPath operation searching only the last
9308 * element in document order
9309 *
9310 * Returns the number of node traversed
9311 */
9312static int
9313xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9314 xmlNodePtr * last)
9315{
9316 int total = 0, cur;
9317 xmlXPathCompExprPtr comp;
9318 xmlXPathObjectPtr arg1, arg2;
9319
Daniel Veillard556c6682001-10-06 09:59:51 +00009320 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009321 comp = ctxt->comp;
9322 switch (op->op) {
9323 case XPATH_OP_END:
9324 return (0);
9325 case XPATH_OP_UNION:
9326 total =
9327 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009328 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009329 if ((ctxt->value != NULL)
9330 && (ctxt->value->type == XPATH_NODESET)
9331 && (ctxt->value->nodesetval != NULL)
9332 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9333 /*
9334 * limit tree traversing to first node in the result
9335 */
9336 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9337 *last =
9338 ctxt->value->nodesetval->nodeTab[ctxt->value->
9339 nodesetval->nodeNr -
9340 1];
9341 }
9342 cur =
9343 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009344 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009345 if ((ctxt->value != NULL)
9346 && (ctxt->value->type == XPATH_NODESET)
9347 && (ctxt->value->nodesetval != NULL)
9348 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9349 }
9350 CHECK_TYPE0(XPATH_NODESET);
9351 arg2 = valuePop(ctxt);
9352
9353 CHECK_TYPE0(XPATH_NODESET);
9354 arg1 = valuePop(ctxt);
9355
9356 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9357 arg2->nodesetval);
9358 valuePush(ctxt, arg1);
9359 xmlXPathFreeObject(arg2);
9360 /* optimizer */
9361 if (total > cur)
9362 xmlXPathCompSwap(op);
9363 return (total + cur);
9364 case XPATH_OP_ROOT:
9365 xmlXPathRoot(ctxt);
9366 return (0);
9367 case XPATH_OP_NODE:
9368 if (op->ch1 != -1)
9369 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009370 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009371 if (op->ch2 != -1)
9372 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009373 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009374 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9375 return (total);
9376 case XPATH_OP_RESET:
9377 if (op->ch1 != -1)
9378 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009379 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009380 if (op->ch2 != -1)
9381 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009382 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009383 ctxt->context->node = NULL;
9384 return (total);
9385 case XPATH_OP_COLLECT:{
9386 if (op->ch1 == -1)
9387 return (0);
9388
9389 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009390 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009391
9392 /*
9393 * Optimization for [n] selection where n is a number
9394 */
9395 if ((op->ch2 != -1) &&
9396 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9397 (comp->steps[op->ch2].ch1 == -1) &&
9398 (comp->steps[op->ch2].ch2 != -1) &&
9399 (comp->steps[comp->steps[op->ch2].ch2].op ==
9400 XPATH_OP_VALUE)) {
9401 xmlXPathObjectPtr val;
9402
9403 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9404 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9405 int indx = (int) val->floatval;
9406
9407 if (val->floatval == (float) indx) {
9408 total +=
9409 xmlXPathNodeCollectAndTestNth(ctxt, op,
9410 indx, NULL,
9411 last);
9412 return (total);
9413 }
9414 }
9415 }
9416 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9417 return (total);
9418 }
9419 case XPATH_OP_VALUE:
9420 valuePush(ctxt,
9421 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9422 return (0);
9423 case XPATH_OP_SORT:
9424 if (op->ch1 != -1)
9425 total +=
9426 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9427 last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009428 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009429 if ((ctxt->value != NULL)
9430 && (ctxt->value->type == XPATH_NODESET)
9431 && (ctxt->value->nodesetval != NULL))
9432 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9433 return (total);
9434 default:
9435 return (xmlXPathCompOpEval(ctxt, op));
9436 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009437}
9438
Owen Taylor3473f882001-02-23 17:55:21 +00009439/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009440 * xmlXPathCompOpEval:
9441 * @ctxt: the XPath parser context with the compiled expression
9442 * @op: an XPath compiled operation
9443 *
9444 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009445 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009446 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009447static int
9448xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9449{
9450 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009451 int equal, ret;
9452 xmlXPathCompExprPtr comp;
9453 xmlXPathObjectPtr arg1, arg2;
9454
Daniel Veillard556c6682001-10-06 09:59:51 +00009455 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009456 comp = ctxt->comp;
9457 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009458 case XPATH_OP_END:
9459 return (0);
9460 case XPATH_OP_AND:
9461 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009462 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009463 xmlXPathBooleanFunction(ctxt, 1);
9464 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9465 return (total);
9466 arg2 = valuePop(ctxt);
9467 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009468 if (ctxt->error) {
9469 xmlXPathFreeObject(arg2);
9470 return(0);
9471 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009472 xmlXPathBooleanFunction(ctxt, 1);
9473 arg1 = valuePop(ctxt);
9474 arg1->boolval &= arg2->boolval;
9475 valuePush(ctxt, arg1);
9476 xmlXPathFreeObject(arg2);
9477 return (total);
9478 case XPATH_OP_OR:
9479 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009480 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009481 xmlXPathBooleanFunction(ctxt, 1);
9482 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9483 return (total);
9484 arg2 = valuePop(ctxt);
9485 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009486 if (ctxt->error) {
9487 xmlXPathFreeObject(arg2);
9488 return(0);
9489 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009490 xmlXPathBooleanFunction(ctxt, 1);
9491 arg1 = valuePop(ctxt);
9492 arg1->boolval |= arg2->boolval;
9493 valuePush(ctxt, arg1);
9494 xmlXPathFreeObject(arg2);
9495 return (total);
9496 case XPATH_OP_EQUAL:
9497 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009498 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009499 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009500 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009501 equal = xmlXPathEqualValues(ctxt);
9502 if (op->value)
9503 valuePush(ctxt, xmlXPathNewBoolean(equal));
9504 else
9505 valuePush(ctxt, xmlXPathNewBoolean(!equal));
9506 return (total);
9507 case XPATH_OP_CMP:
9508 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009509 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009510 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009511 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009512 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
9513 valuePush(ctxt, xmlXPathNewBoolean(ret));
9514 return (total);
9515 case XPATH_OP_PLUS:
9516 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009517 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009518 if (op->ch2 != -1)
9519 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009520 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009521 if (op->value == 0)
9522 xmlXPathSubValues(ctxt);
9523 else if (op->value == 1)
9524 xmlXPathAddValues(ctxt);
9525 else if (op->value == 2)
9526 xmlXPathValueFlipSign(ctxt);
9527 else if (op->value == 3) {
9528 CAST_TO_NUMBER;
9529 CHECK_TYPE0(XPATH_NUMBER);
9530 }
9531 return (total);
9532 case XPATH_OP_MULT:
9533 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009534 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009535 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009536 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009537 if (op->value == 0)
9538 xmlXPathMultValues(ctxt);
9539 else if (op->value == 1)
9540 xmlXPathDivValues(ctxt);
9541 else if (op->value == 2)
9542 xmlXPathModValues(ctxt);
9543 return (total);
9544 case XPATH_OP_UNION:
9545 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009546 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009547 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009548 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009549 CHECK_TYPE0(XPATH_NODESET);
9550 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009551
Daniel Veillardf06307e2001-07-03 10:35:50 +00009552 CHECK_TYPE0(XPATH_NODESET);
9553 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009554
Daniel Veillardf06307e2001-07-03 10:35:50 +00009555 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9556 arg2->nodesetval);
9557 valuePush(ctxt, arg1);
9558 xmlXPathFreeObject(arg2);
9559 return (total);
9560 case XPATH_OP_ROOT:
9561 xmlXPathRoot(ctxt);
9562 return (total);
9563 case XPATH_OP_NODE:
9564 if (op->ch1 != -1)
9565 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009566 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009567 if (op->ch2 != -1)
9568 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009569 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009570 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9571 return (total);
9572 case XPATH_OP_RESET:
9573 if (op->ch1 != -1)
9574 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009575 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009576 if (op->ch2 != -1)
9577 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009578 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009579 ctxt->context->node = NULL;
9580 return (total);
9581 case XPATH_OP_COLLECT:{
9582 if (op->ch1 == -1)
9583 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009584
Daniel Veillardf06307e2001-07-03 10:35:50 +00009585 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009586 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009587
Daniel Veillardf06307e2001-07-03 10:35:50 +00009588 /*
9589 * Optimization for [n] selection where n is a number
9590 */
9591 if ((op->ch2 != -1) &&
9592 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9593 (comp->steps[op->ch2].ch1 == -1) &&
9594 (comp->steps[op->ch2].ch2 != -1) &&
9595 (comp->steps[comp->steps[op->ch2].ch2].op ==
9596 XPATH_OP_VALUE)) {
9597 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +00009598
Daniel Veillardf06307e2001-07-03 10:35:50 +00009599 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9600 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9601 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009602
Daniel Veillardf06307e2001-07-03 10:35:50 +00009603 if (val->floatval == (float) indx) {
9604 total +=
9605 xmlXPathNodeCollectAndTestNth(ctxt, op,
9606 indx, NULL,
9607 NULL);
9608 return (total);
9609 }
9610 }
9611 }
9612 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
9613 return (total);
9614 }
9615 case XPATH_OP_VALUE:
9616 valuePush(ctxt,
9617 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9618 return (total);
9619 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +00009620 xmlXPathObjectPtr val;
9621
Daniel Veillardf06307e2001-07-03 10:35:50 +00009622 if (op->ch1 != -1)
9623 total +=
9624 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009625 if (op->value5 == NULL) {
9626 val = xmlXPathVariableLookup(ctxt->context, op->value4);
9627 if (val == NULL) {
9628 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
9629 return(0);
9630 }
9631 valuePush(ctxt, val);
9632 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009633 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009634
Daniel Veillardf06307e2001-07-03 10:35:50 +00009635 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9636 if (URI == NULL) {
9637 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009638 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009639 op->value4, op->value5);
9640 return (total);
9641 }
Daniel Veillard556c6682001-10-06 09:59:51 +00009642 val = xmlXPathVariableLookupNS(ctxt->context,
9643 op->value4, URI);
9644 if (val == NULL) {
9645 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
9646 return(0);
9647 }
9648 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009649 }
9650 return (total);
9651 }
9652 case XPATH_OP_FUNCTION:{
9653 xmlXPathFunction func;
9654 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +00009655 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009656
9657 if (op->ch1 != -1)
9658 total +=
9659 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009660 if (ctxt->valueNr < op->value) {
9661 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009662 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +00009663 ctxt->error = XPATH_INVALID_OPERAND;
9664 return (total);
9665 }
9666 for (i = 0; i < op->value; i++)
9667 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
9668 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009669 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +00009670 ctxt->error = XPATH_INVALID_OPERAND;
9671 return (total);
9672 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009673 if (op->cache != NULL)
9674 func = (xmlXPathFunction) op->cache;
9675 else {
9676 const xmlChar *URI = NULL;
9677
9678 if (op->value5 == NULL)
9679 func =
9680 xmlXPathFunctionLookup(ctxt->context,
9681 op->value4);
9682 else {
9683 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9684 if (URI == NULL) {
9685 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009686 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009687 op->value4, op->value5);
9688 return (total);
9689 }
9690 func = xmlXPathFunctionLookupNS(ctxt->context,
9691 op->value4, URI);
9692 }
9693 if (func == NULL) {
9694 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009695 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009696 op->value4);
9697 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009698 }
9699 op->cache = (void *) func;
9700 op->cacheURI = (void *) URI;
9701 }
9702 oldFunc = ctxt->context->function;
9703 oldFuncURI = ctxt->context->functionURI;
9704 ctxt->context->function = op->value4;
9705 ctxt->context->functionURI = op->cacheURI;
9706 func(ctxt, op->value);
9707 ctxt->context->function = oldFunc;
9708 ctxt->context->functionURI = oldFuncURI;
9709 return (total);
9710 }
9711 case XPATH_OP_ARG:
9712 if (op->ch1 != -1)
9713 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009714 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009715 if (op->ch2 != -1)
9716 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009717 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009718 return (total);
9719 case XPATH_OP_PREDICATE:
9720 case XPATH_OP_FILTER:{
9721 xmlXPathObjectPtr res;
9722 xmlXPathObjectPtr obj, tmp;
9723 xmlNodeSetPtr newset = NULL;
9724 xmlNodeSetPtr oldset;
9725 xmlNodePtr oldnode;
9726 int i;
9727
9728 /*
9729 * Optimization for ()[1] selection i.e. the first elem
9730 */
9731 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9732 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9733 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
9734 xmlXPathObjectPtr val;
9735
9736 val = comp->steps[op->ch2].value4;
9737 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
9738 (val->floatval == 1.0)) {
9739 xmlNodePtr first = NULL;
9740
9741 total +=
9742 xmlXPathCompOpEvalFirst(ctxt,
9743 &comp->steps[op->ch1],
9744 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009745 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009746 /*
9747 * The nodeset should be in document order,
9748 * Keep only the first value
9749 */
9750 if ((ctxt->value != NULL) &&
9751 (ctxt->value->type == XPATH_NODESET) &&
9752 (ctxt->value->nodesetval != NULL) &&
9753 (ctxt->value->nodesetval->nodeNr > 1))
9754 ctxt->value->nodesetval->nodeNr = 1;
9755 return (total);
9756 }
9757 }
9758 /*
9759 * Optimization for ()[last()] selection i.e. the last elem
9760 */
9761 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9762 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9763 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
9764 int f = comp->steps[op->ch2].ch1;
9765
9766 if ((f != -1) &&
9767 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
9768 (comp->steps[f].value5 == NULL) &&
9769 (comp->steps[f].value == 0) &&
9770 (comp->steps[f].value4 != NULL) &&
9771 (xmlStrEqual
9772 (comp->steps[f].value4, BAD_CAST "last"))) {
9773 xmlNodePtr last = NULL;
9774
9775 total +=
9776 xmlXPathCompOpEvalLast(ctxt,
9777 &comp->steps[op->ch1],
9778 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009779 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009780 /*
9781 * The nodeset should be in document order,
9782 * Keep only the last value
9783 */
9784 if ((ctxt->value != NULL) &&
9785 (ctxt->value->type == XPATH_NODESET) &&
9786 (ctxt->value->nodesetval != NULL) &&
9787 (ctxt->value->nodesetval->nodeTab != NULL) &&
9788 (ctxt->value->nodesetval->nodeNr > 1)) {
9789 ctxt->value->nodesetval->nodeTab[0] =
9790 ctxt->value->nodesetval->nodeTab[ctxt->
9791 value->
9792 nodesetval->
9793 nodeNr -
9794 1];
9795 ctxt->value->nodesetval->nodeNr = 1;
9796 }
9797 return (total);
9798 }
9799 }
9800
9801 if (op->ch1 != -1)
9802 total +=
9803 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009804 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009805 if (op->ch2 == -1)
9806 return (total);
9807 if (ctxt->value == NULL)
9808 return (total);
9809
9810 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009811
9812#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00009813 /*
9814 * Hum are we filtering the result of an XPointer expression
9815 */
9816 if (ctxt->value->type == XPATH_LOCATIONSET) {
9817 xmlLocationSetPtr newlocset = NULL;
9818 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009819
Daniel Veillardf06307e2001-07-03 10:35:50 +00009820 /*
9821 * Extract the old locset, and then evaluate the result of the
9822 * expression for all the element in the locset. use it to grow
9823 * up a new locset.
9824 */
9825 CHECK_TYPE0(XPATH_LOCATIONSET);
9826 obj = valuePop(ctxt);
9827 oldlocset = obj->user;
9828 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009829
Daniel Veillardf06307e2001-07-03 10:35:50 +00009830 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
9831 ctxt->context->contextSize = 0;
9832 ctxt->context->proximityPosition = 0;
9833 if (op->ch2 != -1)
9834 total +=
9835 xmlXPathCompOpEval(ctxt,
9836 &comp->steps[op->ch2]);
9837 res = valuePop(ctxt);
9838 if (res != NULL)
9839 xmlXPathFreeObject(res);
9840 valuePush(ctxt, obj);
9841 CHECK_ERROR0;
9842 return (total);
9843 }
9844 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009845
Daniel Veillardf06307e2001-07-03 10:35:50 +00009846 for (i = 0; i < oldlocset->locNr; i++) {
9847 /*
9848 * Run the evaluation with a node list made of a
9849 * single item in the nodelocset.
9850 */
9851 ctxt->context->node = oldlocset->locTab[i]->user;
9852 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9853 valuePush(ctxt, tmp);
9854 ctxt->context->contextSize = oldlocset->locNr;
9855 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009856
Daniel Veillardf06307e2001-07-03 10:35:50 +00009857 if (op->ch2 != -1)
9858 total +=
9859 xmlXPathCompOpEval(ctxt,
9860 &comp->steps[op->ch2]);
9861 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009862
Daniel Veillardf06307e2001-07-03 10:35:50 +00009863 /*
9864 * The result of the evaluation need to be tested to
9865 * decided whether the filter succeeded or not
9866 */
9867 res = valuePop(ctxt);
9868 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
9869 xmlXPtrLocationSetAdd(newlocset,
9870 xmlXPathObjectCopy
9871 (oldlocset->locTab[i]));
9872 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009873
Daniel Veillardf06307e2001-07-03 10:35:50 +00009874 /*
9875 * Cleanup
9876 */
9877 if (res != NULL)
9878 xmlXPathFreeObject(res);
9879 if (ctxt->value == tmp) {
9880 res = valuePop(ctxt);
9881 xmlXPathFreeObject(res);
9882 }
9883
9884 ctxt->context->node = NULL;
9885 }
9886
9887 /*
9888 * The result is used as the new evaluation locset.
9889 */
9890 xmlXPathFreeObject(obj);
9891 ctxt->context->node = NULL;
9892 ctxt->context->contextSize = -1;
9893 ctxt->context->proximityPosition = -1;
9894 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
9895 ctxt->context->node = oldnode;
9896 return (total);
9897 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009898#endif /* LIBXML_XPTR_ENABLED */
9899
Daniel Veillardf06307e2001-07-03 10:35:50 +00009900 /*
9901 * Extract the old set, and then evaluate the result of the
9902 * expression for all the element in the set. use it to grow
9903 * up a new set.
9904 */
9905 CHECK_TYPE0(XPATH_NODESET);
9906 obj = valuePop(ctxt);
9907 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00009908
Daniel Veillardf06307e2001-07-03 10:35:50 +00009909 oldnode = ctxt->context->node;
9910 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009911
Daniel Veillardf06307e2001-07-03 10:35:50 +00009912 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
9913 ctxt->context->contextSize = 0;
9914 ctxt->context->proximityPosition = 0;
9915 if (op->ch2 != -1)
9916 total +=
9917 xmlXPathCompOpEval(ctxt,
9918 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009919 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009920 res = valuePop(ctxt);
9921 if (res != NULL)
9922 xmlXPathFreeObject(res);
9923 valuePush(ctxt, obj);
9924 ctxt->context->node = oldnode;
9925 CHECK_ERROR0;
9926 } else {
9927 /*
9928 * Initialize the new set.
9929 */
9930 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009931
Daniel Veillardf06307e2001-07-03 10:35:50 +00009932 for (i = 0; i < oldset->nodeNr; i++) {
9933 /*
9934 * Run the evaluation with a node list made of
9935 * a single item in the nodeset.
9936 */
9937 ctxt->context->node = oldset->nodeTab[i];
9938 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9939 valuePush(ctxt, tmp);
9940 ctxt->context->contextSize = oldset->nodeNr;
9941 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009942
Daniel Veillardf06307e2001-07-03 10:35:50 +00009943 if (op->ch2 != -1)
9944 total +=
9945 xmlXPathCompOpEval(ctxt,
9946 &comp->steps[op->ch2]);
9947 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009948
Daniel Veillardf06307e2001-07-03 10:35:50 +00009949 /*
9950 * The result of the evaluation need to be tested to
9951 * decided whether the filter succeeded or not
9952 */
9953 res = valuePop(ctxt);
9954 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
9955 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
9956 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009957
Daniel Veillardf06307e2001-07-03 10:35:50 +00009958 /*
9959 * Cleanup
9960 */
9961 if (res != NULL)
9962 xmlXPathFreeObject(res);
9963 if (ctxt->value == tmp) {
9964 res = valuePop(ctxt);
9965 xmlXPathFreeObject(res);
9966 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009967
Daniel Veillardf06307e2001-07-03 10:35:50 +00009968 ctxt->context->node = NULL;
9969 }
9970
9971 /*
9972 * The result is used as the new evaluation set.
9973 */
9974 xmlXPathFreeObject(obj);
9975 ctxt->context->node = NULL;
9976 ctxt->context->contextSize = -1;
9977 ctxt->context->proximityPosition = -1;
9978 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
9979 }
9980 ctxt->context->node = oldnode;
9981 return (total);
9982 }
9983 case XPATH_OP_SORT:
9984 if (op->ch1 != -1)
9985 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009986 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009987 if ((ctxt->value != NULL) &&
9988 (ctxt->value->type == XPATH_NODESET) &&
9989 (ctxt->value->nodesetval != NULL))
9990 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9991 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009992#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00009993 case XPATH_OP_RANGETO:{
9994 xmlXPathObjectPtr range;
9995 xmlXPathObjectPtr res, obj;
9996 xmlXPathObjectPtr tmp;
9997 xmlLocationSetPtr newset = NULL;
9998 xmlNodeSetPtr oldset;
9999 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010000
Daniel Veillardf06307e2001-07-03 10:35:50 +000010001 if (op->ch1 != -1)
10002 total +=
10003 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10004 if (op->ch2 == -1)
10005 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010006
Daniel Veillardf06307e2001-07-03 10:35:50 +000010007 CHECK_TYPE0(XPATH_NODESET);
10008 obj = valuePop(ctxt);
10009 oldset = obj->nodesetval;
10010 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010011
Daniel Veillardf06307e2001-07-03 10:35:50 +000010012 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010013
Daniel Veillardf06307e2001-07-03 10:35:50 +000010014 if (oldset != NULL) {
10015 for (i = 0; i < oldset->nodeNr; i++) {
10016 /*
10017 * Run the evaluation with a node list made of a single item
10018 * in the nodeset.
10019 */
10020 ctxt->context->node = oldset->nodeTab[i];
10021 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10022 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010023
Daniel Veillardf06307e2001-07-03 10:35:50 +000010024 if (op->ch2 != -1)
10025 total +=
10026 xmlXPathCompOpEval(ctxt,
10027 &comp->steps[op->ch2]);
10028 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010029
Daniel Veillardf06307e2001-07-03 10:35:50 +000010030 /*
10031 * The result of the evaluation need to be tested to
10032 * decided whether the filter succeeded or not
10033 */
10034 res = valuePop(ctxt);
10035 range =
10036 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10037 res);
10038 if (range != NULL) {
10039 xmlXPtrLocationSetAdd(newset, range);
10040 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010041
Daniel Veillardf06307e2001-07-03 10:35:50 +000010042 /*
10043 * Cleanup
10044 */
10045 if (res != NULL)
10046 xmlXPathFreeObject(res);
10047 if (ctxt->value == tmp) {
10048 res = valuePop(ctxt);
10049 xmlXPathFreeObject(res);
10050 }
10051
10052 ctxt->context->node = NULL;
10053 }
10054 }
10055
10056 /*
10057 * The result is used as the new evaluation set.
10058 */
10059 xmlXPathFreeObject(obj);
10060 ctxt->context->node = NULL;
10061 ctxt->context->contextSize = -1;
10062 ctxt->context->proximityPosition = -1;
10063 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
10064 return (total);
10065 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010066#endif /* LIBXML_XPTR_ENABLED */
10067 }
10068 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010069 "XPath: unknown precompiled operation %d\n", op->op);
10070 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010071}
10072
10073/**
10074 * xmlXPathRunEval:
10075 * @ctxt: the XPath parser context with the compiled expression
10076 *
10077 * Evaluate the Precompiled XPath expression in the given context.
10078 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010079static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010080xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10081 xmlXPathCompExprPtr comp;
10082
10083 if ((ctxt == NULL) || (ctxt->comp == NULL))
10084 return;
10085
10086 if (ctxt->valueTab == NULL) {
10087 /* Allocate the value stack */
10088 ctxt->valueTab = (xmlXPathObjectPtr *)
10089 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10090 if (ctxt->valueTab == NULL) {
10091 xmlFree(ctxt);
10092 xmlGenericError(xmlGenericErrorContext,
10093 "xmlXPathRunEval: out of memory\n");
10094 return;
10095 }
10096 ctxt->valueNr = 0;
10097 ctxt->valueMax = 10;
10098 ctxt->value = NULL;
10099 }
10100 comp = ctxt->comp;
10101 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10102}
10103
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010104/************************************************************************
10105 * *
10106 * Public interfaces *
10107 * *
10108 ************************************************************************/
10109
10110/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010111 * xmlXPathEvalPredicate:
10112 * @ctxt: the XPath context
10113 * @res: the Predicate Expression evaluation result
10114 *
10115 * Evaluate a predicate result for the current node.
10116 * A PredicateExpr is evaluated by evaluating the Expr and converting
10117 * the result to a boolean. If the result is a number, the result will
10118 * be converted to true if the number is equal to the position of the
10119 * context node in the context node list (as returned by the position
10120 * function) and will be converted to false otherwise; if the result
10121 * is not a number, then the result will be converted as if by a call
10122 * to the boolean function.
10123 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010124 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010125 */
10126int
10127xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
10128 if (res == NULL) return(0);
10129 switch (res->type) {
10130 case XPATH_BOOLEAN:
10131 return(res->boolval);
10132 case XPATH_NUMBER:
10133 return(res->floatval == ctxt->proximityPosition);
10134 case XPATH_NODESET:
10135 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010136 if (res->nodesetval == NULL)
10137 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010138 return(res->nodesetval->nodeNr != 0);
10139 case XPATH_STRING:
10140 return((res->stringval != NULL) &&
10141 (xmlStrlen(res->stringval) != 0));
10142 default:
10143 STRANGE
10144 }
10145 return(0);
10146}
10147
10148/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010149 * xmlXPathEvaluatePredicateResult:
10150 * @ctxt: the XPath Parser context
10151 * @res: the Predicate Expression evaluation result
10152 *
10153 * Evaluate a predicate result for the current node.
10154 * A PredicateExpr is evaluated by evaluating the Expr and converting
10155 * the result to a boolean. If the result is a number, the result will
10156 * be converted to true if the number is equal to the position of the
10157 * context node in the context node list (as returned by the position
10158 * function) and will be converted to false otherwise; if the result
10159 * is not a number, then the result will be converted as if by a call
10160 * to the boolean function.
10161 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010162 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010163 */
10164int
10165xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10166 xmlXPathObjectPtr res) {
10167 if (res == NULL) return(0);
10168 switch (res->type) {
10169 case XPATH_BOOLEAN:
10170 return(res->boolval);
10171 case XPATH_NUMBER:
10172 return(res->floatval == ctxt->context->proximityPosition);
10173 case XPATH_NODESET:
10174 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000010175 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000010176 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010177 return(res->nodesetval->nodeNr != 0);
10178 case XPATH_STRING:
10179 return((res->stringval != NULL) &&
10180 (xmlStrlen(res->stringval) != 0));
10181 default:
10182 STRANGE
10183 }
10184 return(0);
10185}
10186
10187/**
10188 * xmlXPathCompile:
10189 * @str: the XPath expression
10190 *
10191 * Compile an XPath expression
10192 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010193 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010194 * the caller has to free the object.
10195 */
10196xmlXPathCompExprPtr
10197xmlXPathCompile(const xmlChar *str) {
10198 xmlXPathParserContextPtr ctxt;
10199 xmlXPathCompExprPtr comp;
10200
10201 xmlXPathInit();
10202
10203 ctxt = xmlXPathNewParserContext(str, NULL);
10204 xmlXPathCompileExpr(ctxt);
10205
Daniel Veillard40af6492001-04-22 08:50:55 +000010206 if (*ctxt->cur != 0) {
10207 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10208 comp = NULL;
10209 } else {
10210 comp = ctxt->comp;
10211 ctxt->comp = NULL;
10212 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010213 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010214#ifdef DEBUG_EVAL_COUNTS
10215 if (comp != NULL) {
10216 comp->string = xmlStrdup(str);
10217 comp->nb = 0;
10218 }
10219#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010220 return(comp);
10221}
10222
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010223/**
10224 * xmlXPathCompiledEval:
10225 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000010226 * @ctx: the XPath context
10227 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010228 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000010229 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010230 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000010231 * the caller has to free the object.
10232 */
10233xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010234xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000010235 xmlXPathParserContextPtr ctxt;
10236 xmlXPathObjectPtr res, tmp, init = NULL;
10237 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000010238#ifndef LIBXML_THREAD_ENABLED
10239 static int reentance = 0;
10240#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010241
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010242 if ((comp == NULL) || (ctx == NULL))
10243 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010244 xmlXPathInit();
10245
10246 CHECK_CONTEXT(ctx)
10247
Daniel Veillard81463942001-10-16 12:34:39 +000010248#ifndef LIBXML_THREAD_ENABLED
10249 reentance++;
10250 if (reentance > 1)
10251 xmlXPathDisableOptimizer = 1;
10252#endif
10253
Daniel Veillardf06307e2001-07-03 10:35:50 +000010254#ifdef DEBUG_EVAL_COUNTS
10255 comp->nb++;
10256 if ((comp->string != NULL) && (comp->nb > 100)) {
10257 fprintf(stderr, "100 x %s\n", comp->string);
10258 comp->nb = 0;
10259 }
10260#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010261 ctxt = xmlXPathCompParserContext(comp, ctx);
10262 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010263
10264 if (ctxt->value == NULL) {
10265 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010266 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000010267 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000010268 } else {
10269 res = valuePop(ctxt);
10270 }
10271
Daniel Veillardf06307e2001-07-03 10:35:50 +000010272
Owen Taylor3473f882001-02-23 17:55:21 +000010273 do {
10274 tmp = valuePop(ctxt);
10275 if (tmp != NULL) {
10276 if (tmp != init)
10277 stack++;
10278 xmlXPathFreeObject(tmp);
10279 }
10280 } while (tmp != NULL);
10281 if ((stack != 0) && (res != NULL)) {
10282 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010283 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000010284 stack);
10285 }
10286 if (ctxt->error != XPATH_EXPRESSION_OK) {
10287 xmlXPathFreeObject(res);
10288 res = NULL;
10289 }
10290
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010291
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010292 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010293 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000010294#ifndef LIBXML_THREAD_ENABLED
10295 reentance--;
10296#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010297 return(res);
10298}
10299
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010300/**
10301 * xmlXPathEvalExpr:
10302 * @ctxt: the XPath Parser context
10303 *
10304 * Parse and evaluate an XPath expression in the given context,
10305 * then push the result on the context stack
10306 */
10307void
10308xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
10309 xmlXPathCompileExpr(ctxt);
10310 xmlXPathRunEval(ctxt);
10311}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010312
10313/**
10314 * xmlXPathEval:
10315 * @str: the XPath expression
10316 * @ctx: the XPath context
10317 *
10318 * Evaluate the XPath Location Path in the given context.
10319 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010320 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010321 * the caller has to free the object.
10322 */
10323xmlXPathObjectPtr
10324xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
10325 xmlXPathParserContextPtr ctxt;
10326 xmlXPathObjectPtr res, tmp, init = NULL;
10327 int stack = 0;
10328
10329 xmlXPathInit();
10330
10331 CHECK_CONTEXT(ctx)
10332
10333 ctxt = xmlXPathNewParserContext(str, ctx);
10334 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010335
10336 if (ctxt->value == NULL) {
10337 xmlGenericError(xmlGenericErrorContext,
10338 "xmlXPathEval: evaluation failed\n");
10339 res = NULL;
10340 } else if (*ctxt->cur != 0) {
10341 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10342 res = NULL;
10343 } else {
10344 res = valuePop(ctxt);
10345 }
10346
10347 do {
10348 tmp = valuePop(ctxt);
10349 if (tmp != NULL) {
10350 if (tmp != init)
10351 stack++;
10352 xmlXPathFreeObject(tmp);
10353 }
10354 } while (tmp != NULL);
10355 if ((stack != 0) && (res != NULL)) {
10356 xmlGenericError(xmlGenericErrorContext,
10357 "xmlXPathEval: %d object left on the stack\n",
10358 stack);
10359 }
10360 if (ctxt->error != XPATH_EXPRESSION_OK) {
10361 xmlXPathFreeObject(res);
10362 res = NULL;
10363 }
10364
Owen Taylor3473f882001-02-23 17:55:21 +000010365 xmlXPathFreeParserContext(ctxt);
10366 return(res);
10367}
10368
10369/**
10370 * xmlXPathEvalExpression:
10371 * @str: the XPath expression
10372 * @ctxt: the XPath context
10373 *
10374 * Evaluate the XPath expression in the given context.
10375 *
10376 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
10377 * the caller has to free the object.
10378 */
10379xmlXPathObjectPtr
10380xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
10381 xmlXPathParserContextPtr pctxt;
10382 xmlXPathObjectPtr res, tmp;
10383 int stack = 0;
10384
10385 xmlXPathInit();
10386
10387 CHECK_CONTEXT(ctxt)
10388
10389 pctxt = xmlXPathNewParserContext(str, ctxt);
10390 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010391
10392 if (*pctxt->cur != 0) {
10393 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10394 res = NULL;
10395 } else {
10396 res = valuePop(pctxt);
10397 }
10398 do {
10399 tmp = valuePop(pctxt);
10400 if (tmp != NULL) {
10401 xmlXPathFreeObject(tmp);
10402 stack++;
10403 }
10404 } while (tmp != NULL);
10405 if ((stack != 0) && (res != NULL)) {
10406 xmlGenericError(xmlGenericErrorContext,
10407 "xmlXPathEvalExpression: %d object left on the stack\n",
10408 stack);
10409 }
10410 xmlXPathFreeParserContext(pctxt);
10411 return(res);
10412}
10413
10414/**
10415 * xmlXPathRegisterAllFunctions:
10416 * @ctxt: the XPath context
10417 *
10418 * Registers all default XPath functions in this context
10419 */
10420void
10421xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
10422{
10423 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
10424 xmlXPathBooleanFunction);
10425 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
10426 xmlXPathCeilingFunction);
10427 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
10428 xmlXPathCountFunction);
10429 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
10430 xmlXPathConcatFunction);
10431 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
10432 xmlXPathContainsFunction);
10433 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
10434 xmlXPathIdFunction);
10435 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
10436 xmlXPathFalseFunction);
10437 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
10438 xmlXPathFloorFunction);
10439 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
10440 xmlXPathLastFunction);
10441 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
10442 xmlXPathLangFunction);
10443 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
10444 xmlXPathLocalNameFunction);
10445 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
10446 xmlXPathNotFunction);
10447 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
10448 xmlXPathNameFunction);
10449 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
10450 xmlXPathNamespaceURIFunction);
10451 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
10452 xmlXPathNormalizeFunction);
10453 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
10454 xmlXPathNumberFunction);
10455 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
10456 xmlXPathPositionFunction);
10457 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
10458 xmlXPathRoundFunction);
10459 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
10460 xmlXPathStringFunction);
10461 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
10462 xmlXPathStringLengthFunction);
10463 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
10464 xmlXPathStartsWithFunction);
10465 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
10466 xmlXPathSubstringFunction);
10467 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
10468 xmlXPathSubstringBeforeFunction);
10469 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
10470 xmlXPathSubstringAfterFunction);
10471 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
10472 xmlXPathSumFunction);
10473 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
10474 xmlXPathTrueFunction);
10475 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
10476 xmlXPathTranslateFunction);
10477}
10478
10479#endif /* LIBXML_XPATH_ENABLED */