blob: 1171996a6add62cdf67d583e7d0f15e7d6a77101 [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 *
Owen Taylor3473f882001-02-23 17:55:21 +000015 */
16
Daniel Veillard34ce8be2002-03-18 19:37:11 +000017#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000018#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000019#ifdef LIBXML_XPATH_ENABLED
20
Owen Taylor3473f882001-02-23 17:55:21 +000021#include <string.h>
22
23#ifdef HAVE_SYS_TYPES_H
24#include <sys/types.h>
25#endif
26#ifdef HAVE_MATH_H
27#include <math.h>
28#endif
29#ifdef HAVE_FLOAT_H
30#include <float.h>
31#endif
Owen Taylor3473f882001-02-23 17:55:21 +000032#ifdef HAVE_CTYPE_H
33#include <ctype.h>
34#endif
Daniel Veillard5792e162001-04-30 17:44:45 +000035#ifdef HAVE_SIGNAL_H
Daniel Veillardb45c43b2001-04-28 17:02:11 +000036#include <signal.h>
Daniel Veillardb45c43b2001-04-28 17:02:11 +000037#endif
Owen Taylor3473f882001-02-23 17:55:21 +000038
39#include <libxml/xmlmemory.h>
40#include <libxml/tree.h>
41#include <libxml/valid.h>
42#include <libxml/xpath.h>
43#include <libxml/xpathInternals.h>
44#include <libxml/parserInternals.h>
45#include <libxml/hash.h>
46#ifdef LIBXML_XPTR_ENABLED
47#include <libxml/xpointer.h>
48#endif
49#ifdef LIBXML_DEBUG_ENABLED
50#include <libxml/debugXML.h>
51#endif
52#include <libxml/xmlerror.h>
Daniel Veillard81463942001-10-16 12:34:39 +000053#include <libxml/threads.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000054#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000055
Daniel Veillard652d8a92003-02-04 19:28:49 +000056/*
57 * TODO: when compatibility allows remove all "fake node libxslt" strings
58 * the test should just be name[0] = ' '
59 */
Owen Taylor3473f882001-02-23 17:55:21 +000060/* #define DEBUG */
61/* #define DEBUG_STEP */
Daniel Veillardf06307e2001-07-03 10:35:50 +000062/* #define DEBUG_STEP_NTH */
Owen Taylor3473f882001-02-23 17:55:21 +000063/* #define DEBUG_EXPR */
Daniel Veillardf06307e2001-07-03 10:35:50 +000064/* #define DEBUG_EVAL_COUNTS */
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,
Daniel Veillard118aed72002-09-24 14:13:13 +000070 BAD_CAST "xml",
71 NULL
Daniel Veillard20ee8c02001-10-05 09:18:14 +000072};
73static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
Daniel Veillardda423da2002-04-10 19:25:38 +000074#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +000075/*
76 * Optimizer is disabled only when threaded apps are detected while
77 * the library ain't compiled for thread safety.
78 */
79static int xmlXPathDisableOptimizer = 0;
80#endif
Daniel Veillard20ee8c02001-10-05 09:18:14 +000081
Daniel Veillard9e7160d2001-03-18 23:17:47 +000082/************************************************************************
83 * *
84 * Floating point stuff *
85 * *
86 ************************************************************************/
87
Daniel Veillardc0631a62001-09-20 13:56:06 +000088#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +000089#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +000090#endif
Daniel Veillardcda96922001-08-21 10:56:31 +000091#include "trionan.c"
92
Owen Taylor3473f882001-02-23 17:55:21 +000093/*
Owen Taylor3473f882001-02-23 17:55:21 +000094 * The lack of portability of this section of the libc is annoying !
95 */
96double xmlXPathNAN = 0;
97double xmlXPathPINF = 1;
98double xmlXPathNINF = -1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +000099double xmlXPathNZERO = 0;
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000100static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000101
Owen Taylor3473f882001-02-23 17:55:21 +0000102/**
103 * xmlXPathInit:
104 *
105 * Initialize the XPath environment
106 */
107void
108xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000109 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +0000110
Bjorn Reese45029602001-08-21 09:23:53 +0000111 xmlXPathPINF = trio_pinf();
112 xmlXPathNINF = trio_ninf();
113 xmlXPathNAN = trio_nan();
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000114 xmlXPathNZERO = trio_nzero();
Owen Taylor3473f882001-02-23 17:55:21 +0000115
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000116 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000117}
118
Daniel Veillardcda96922001-08-21 10:56:31 +0000119/**
120 * xmlXPathIsNaN:
121 * @val: a double value
122 *
123 * Provides a portable isnan() function to detect whether a double
124 * is a NotaNumber. Based on trio code
125 * http://sourceforge.net/projects/ctrio/
126 *
127 * Returns 1 if the value is a NaN, 0 otherwise
128 */
129int
130xmlXPathIsNaN(double val) {
131 return(trio_isnan(val));
132}
133
134/**
135 * xmlXPathIsInf:
136 * @val: a double value
137 *
138 * Provides a portable isinf() function to detect whether a double
139 * is a +Infinite or -Infinite. Based on trio code
140 * http://sourceforge.net/projects/ctrio/
141 *
142 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
143 */
144int
145xmlXPathIsInf(double val) {
146 return(trio_isinf(val));
147}
148
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000149/**
150 * xmlXPathGetSign:
151 * @val: a double value
152 *
153 * Provides a portable function to detect the sign of a double
154 * Modified from trio code
155 * http://sourceforge.net/projects/ctrio/
156 *
157 * Returns 1 if the value is Negative, 0 if positive
158 */
Daniel Veillard21458c82002-03-27 16:12:22 +0000159static int
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000160xmlXPathGetSign(double val) {
Daniel Veillard21458c82002-03-27 16:12:22 +0000161 return(trio_signbit(val));
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000162}
163
164
Owen Taylor3473f882001-02-23 17:55:21 +0000165/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000166 * *
167 * Parser Types *
168 * *
169 ************************************************************************/
170
171/*
172 * Types are private:
173 */
174
175typedef enum {
176 XPATH_OP_END=0,
177 XPATH_OP_AND,
178 XPATH_OP_OR,
179 XPATH_OP_EQUAL,
180 XPATH_OP_CMP,
181 XPATH_OP_PLUS,
182 XPATH_OP_MULT,
183 XPATH_OP_UNION,
184 XPATH_OP_ROOT,
185 XPATH_OP_NODE,
186 XPATH_OP_RESET,
187 XPATH_OP_COLLECT,
188 XPATH_OP_VALUE,
189 XPATH_OP_VARIABLE,
190 XPATH_OP_FUNCTION,
191 XPATH_OP_ARG,
192 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000193 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000194 XPATH_OP_SORT
195#ifdef LIBXML_XPTR_ENABLED
196 ,XPATH_OP_RANGETO
197#endif
198} xmlXPathOp;
199
200typedef enum {
201 AXIS_ANCESTOR = 1,
202 AXIS_ANCESTOR_OR_SELF,
203 AXIS_ATTRIBUTE,
204 AXIS_CHILD,
205 AXIS_DESCENDANT,
206 AXIS_DESCENDANT_OR_SELF,
207 AXIS_FOLLOWING,
208 AXIS_FOLLOWING_SIBLING,
209 AXIS_NAMESPACE,
210 AXIS_PARENT,
211 AXIS_PRECEDING,
212 AXIS_PRECEDING_SIBLING,
213 AXIS_SELF
214} xmlXPathAxisVal;
215
216typedef enum {
217 NODE_TEST_NONE = 0,
218 NODE_TEST_TYPE = 1,
219 NODE_TEST_PI = 2,
220 NODE_TEST_ALL = 3,
221 NODE_TEST_NS = 4,
222 NODE_TEST_NAME = 5
223} xmlXPathTestVal;
224
225typedef enum {
226 NODE_TYPE_NODE = 0,
227 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
228 NODE_TYPE_TEXT = XML_TEXT_NODE,
229 NODE_TYPE_PI = XML_PI_NODE
230} xmlXPathTypeVal;
231
232
233typedef struct _xmlXPathStepOp xmlXPathStepOp;
234typedef xmlXPathStepOp *xmlXPathStepOpPtr;
235struct _xmlXPathStepOp {
236 xmlXPathOp op;
237 int ch1;
238 int ch2;
239 int value;
240 int value2;
241 int value3;
242 void *value4;
243 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000244 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000245 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000246};
247
248struct _xmlXPathCompExpr {
249 int nbStep;
250 int maxStep;
251 xmlXPathStepOp *steps; /* ops for computation */
252 int last;
Daniel Veillard118aed72002-09-24 14:13:13 +0000253 xmlChar *expr;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000254#ifdef DEBUG_EVAL_COUNTS
255 int nb;
256 xmlChar *string;
257#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000258};
259
260/************************************************************************
261 * *
262 * Parser Type functions *
263 * *
264 ************************************************************************/
265
266/**
267 * xmlXPathNewCompExpr:
268 *
269 * Create a new Xpath component
270 *
271 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
272 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000273static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000274xmlXPathNewCompExpr(void) {
275 xmlXPathCompExprPtr cur;
276
277 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
278 if (cur == NULL) {
279 xmlGenericError(xmlGenericErrorContext,
280 "xmlXPathNewCompExpr : malloc failed\n");
281 return(NULL);
282 }
283 memset(cur, 0, sizeof(xmlXPathCompExpr));
284 cur->maxStep = 10;
285 cur->nbStep = 0;
286 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
287 sizeof(xmlXPathStepOp));
288 if (cur->steps == NULL) {
289 xmlGenericError(xmlGenericErrorContext,
290 "xmlXPathNewCompExpr : malloc failed\n");
291 xmlFree(cur);
292 return(NULL);
293 }
294 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
295 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000296#ifdef DEBUG_EVAL_COUNTS
297 cur->nb = 0;
298#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000299 return(cur);
300}
301
302/**
303 * xmlXPathFreeCompExpr:
304 * @comp: an XPATH comp
305 *
306 * Free up the memory allocated by @comp
307 */
308void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000309xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
310{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000311 xmlXPathStepOpPtr op;
312 int i;
313
314 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000315 return;
316 for (i = 0; i < comp->nbStep; i++) {
317 op = &comp->steps[i];
318 if (op->value4 != NULL) {
319 if (op->op == XPATH_OP_VALUE)
320 xmlXPathFreeObject(op->value4);
321 else
322 xmlFree(op->value4);
323 }
324 if (op->value5 != NULL)
325 xmlFree(op->value5);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000326 }
327 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000328 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000329 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000330#ifdef DEBUG_EVAL_COUNTS
331 if (comp->string != NULL) {
332 xmlFree(comp->string);
333 }
334#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000335 if (comp->expr != NULL) {
336 xmlFree(comp->expr);
337 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000338
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000339 xmlFree(comp);
340}
341
342/**
343 * xmlXPathCompExprAdd:
344 * @comp: the compiled expression
345 * @ch1: first child index
346 * @ch2: second child index
347 * @op: an op
348 * @value: the first int value
349 * @value2: the second int value
350 * @value3: the third int value
351 * @value4: the first string value
352 * @value5: the second string value
353 *
354 * Add an step to an XPath Compiled Expression
355 *
356 * Returns -1 in case of failure, the index otherwise
357 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000358static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000359xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
360 xmlXPathOp op, int value,
361 int value2, int value3, void *value4, void *value5) {
362 if (comp->nbStep >= comp->maxStep) {
363 xmlXPathStepOp *real;
364
365 comp->maxStep *= 2;
366 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
367 comp->maxStep * sizeof(xmlXPathStepOp));
368 if (real == NULL) {
369 comp->maxStep /= 2;
370 xmlGenericError(xmlGenericErrorContext,
371 "xmlXPathCompExprAdd : realloc failed\n");
372 return(-1);
373 }
374 comp->steps = real;
375 }
376 comp->last = comp->nbStep;
377 comp->steps[comp->nbStep].ch1 = ch1;
378 comp->steps[comp->nbStep].ch2 = ch2;
379 comp->steps[comp->nbStep].op = op;
380 comp->steps[comp->nbStep].value = value;
381 comp->steps[comp->nbStep].value2 = value2;
382 comp->steps[comp->nbStep].value3 = value3;
383 comp->steps[comp->nbStep].value4 = value4;
384 comp->steps[comp->nbStep].value5 = value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000385 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000386 return(comp->nbStep++);
387}
388
Daniel Veillardf06307e2001-07-03 10:35:50 +0000389/**
390 * xmlXPathCompSwap:
391 * @comp: the compiled expression
392 * @op: operation index
393 *
394 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000395 */
396static void
397xmlXPathCompSwap(xmlXPathStepOpPtr op) {
398 int tmp;
399
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000400#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000401 /*
402 * Since this manipulates possibly shared variables, this is
403 * disable if one detects that the library is used in a multithreaded
404 * application
405 */
406 if (xmlXPathDisableOptimizer)
407 return;
408#endif
409
Daniel Veillardf06307e2001-07-03 10:35:50 +0000410 tmp = op->ch1;
411 op->ch1 = op->ch2;
412 op->ch2 = tmp;
413}
414
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000415#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
416 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
417 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000418#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
419 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
420 (op), (val), (val2), (val3), (val4), (val5))
421
422#define PUSH_LEAVE_EXPR(op, val, val2) \
423xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
424
425#define PUSH_UNARY_EXPR(op, ch, val, val2) \
426xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
427
428#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
429xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), (val), (val2), 0 ,NULL ,NULL)
430
431/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000432 * *
433 * Debugging related functions *
434 * *
435 ************************************************************************/
436
437#define TODO \
438 xmlGenericError(xmlGenericErrorContext, \
439 "Unimplemented block at %s:%d\n", \
440 __FILE__, __LINE__);
441
442#define STRANGE \
443 xmlGenericError(xmlGenericErrorContext, \
444 "Internal error at %s:%d\n", \
445 __FILE__, __LINE__);
446
447#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000448static void
449xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000450 int i;
451 char shift[100];
452
453 for (i = 0;((i < depth) && (i < 25));i++)
454 shift[2 * i] = shift[2 * i + 1] = ' ';
455 shift[2 * i] = shift[2 * i + 1] = 0;
456 if (cur == NULL) {
457 fprintf(output, shift);
458 fprintf(output, "Node is NULL !\n");
459 return;
460
461 }
462
463 if ((cur->type == XML_DOCUMENT_NODE) ||
464 (cur->type == XML_HTML_DOCUMENT_NODE)) {
465 fprintf(output, shift);
466 fprintf(output, " /\n");
467 } else if (cur->type == XML_ATTRIBUTE_NODE)
468 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
469 else
470 xmlDebugDumpOneNode(output, cur, depth);
471}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000472static void
473xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000474 xmlNodePtr tmp;
475 int i;
476 char shift[100];
477
478 for (i = 0;((i < depth) && (i < 25));i++)
479 shift[2 * i] = shift[2 * i + 1] = ' ';
480 shift[2 * i] = shift[2 * i + 1] = 0;
481 if (cur == NULL) {
482 fprintf(output, shift);
483 fprintf(output, "Node is NULL !\n");
484 return;
485
486 }
487
488 while (cur != NULL) {
489 tmp = cur;
490 cur = cur->next;
491 xmlDebugDumpOneNode(output, tmp, depth);
492 }
493}
Owen Taylor3473f882001-02-23 17:55:21 +0000494
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000495static void
496xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000497 int i;
498 char shift[100];
499
500 for (i = 0;((i < depth) && (i < 25));i++)
501 shift[2 * i] = shift[2 * i + 1] = ' ';
502 shift[2 * i] = shift[2 * i + 1] = 0;
503
504 if (cur == NULL) {
505 fprintf(output, shift);
506 fprintf(output, "NodeSet is NULL !\n");
507 return;
508
509 }
510
Daniel Veillard911f49a2001-04-07 15:39:35 +0000511 if (cur != NULL) {
512 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
513 for (i = 0;i < cur->nodeNr;i++) {
514 fprintf(output, shift);
515 fprintf(output, "%d", i + 1);
516 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
517 }
Owen Taylor3473f882001-02-23 17:55:21 +0000518 }
519}
520
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000521static void
522xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000523 int i;
524 char shift[100];
525
526 for (i = 0;((i < depth) && (i < 25));i++)
527 shift[2 * i] = shift[2 * i + 1] = ' ';
528 shift[2 * i] = shift[2 * i + 1] = 0;
529
530 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
531 fprintf(output, shift);
532 fprintf(output, "Value Tree is NULL !\n");
533 return;
534
535 }
536
537 fprintf(output, shift);
538 fprintf(output, "%d", i + 1);
539 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
540}
Owen Taylor3473f882001-02-23 17:55:21 +0000541#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000542static void
543xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000544 int i;
545 char shift[100];
546
547 for (i = 0;((i < depth) && (i < 25));i++)
548 shift[2 * i] = shift[2 * i + 1] = ' ';
549 shift[2 * i] = shift[2 * i + 1] = 0;
550
551 if (cur == NULL) {
552 fprintf(output, shift);
553 fprintf(output, "LocationSet is NULL !\n");
554 return;
555
556 }
557
558 for (i = 0;i < cur->locNr;i++) {
559 fprintf(output, shift);
560 fprintf(output, "%d : ", i + 1);
561 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
562 }
563}
Daniel Veillard017b1082001-06-21 11:20:21 +0000564#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000565
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000566/**
567 * xmlXPathDebugDumpObject:
568 * @output: the FILE * to dump the output
569 * @cur: the object to inspect
570 * @depth: indentation level
571 *
572 * Dump the content of the object for debugging purposes
573 */
574void
575xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000576 int i;
577 char shift[100];
578
579 for (i = 0;((i < depth) && (i < 25));i++)
580 shift[2 * i] = shift[2 * i + 1] = ' ';
581 shift[2 * i] = shift[2 * i + 1] = 0;
582
583 fprintf(output, shift);
584
585 if (cur == NULL) {
586 fprintf(output, "Object is empty (NULL)\n");
587 return;
588 }
589 switch(cur->type) {
590 case XPATH_UNDEFINED:
591 fprintf(output, "Object is uninitialized\n");
592 break;
593 case XPATH_NODESET:
594 fprintf(output, "Object is a Node Set :\n");
595 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
596 break;
597 case XPATH_XSLT_TREE:
598 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000599 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000600 break;
601 case XPATH_BOOLEAN:
602 fprintf(output, "Object is a Boolean : ");
603 if (cur->boolval) fprintf(output, "true\n");
604 else fprintf(output, "false\n");
605 break;
606 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +0000607 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000608 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000609 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000610 break;
611 case -1:
612 fprintf(output, "Object is a number : -Infinity\n");
613 break;
614 default:
Daniel Veillardcda96922001-08-21 10:56:31 +0000615 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000616 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +0000617 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
618 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000619 } else {
620 fprintf(output, "Object is a number : %0g\n", cur->floatval);
621 }
622 }
Owen Taylor3473f882001-02-23 17:55:21 +0000623 break;
624 case XPATH_STRING:
625 fprintf(output, "Object is a string : ");
626 xmlDebugDumpString(output, cur->stringval);
627 fprintf(output, "\n");
628 break;
629 case XPATH_POINT:
630 fprintf(output, "Object is a point : index %d in node", cur->index);
631 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
632 fprintf(output, "\n");
633 break;
634 case XPATH_RANGE:
635 if ((cur->user2 == NULL) ||
636 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
637 fprintf(output, "Object is a collapsed range :\n");
638 fprintf(output, shift);
639 if (cur->index >= 0)
640 fprintf(output, "index %d in ", cur->index);
641 fprintf(output, "node\n");
642 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
643 depth + 1);
644 } else {
645 fprintf(output, "Object is a range :\n");
646 fprintf(output, shift);
647 fprintf(output, "From ");
648 if (cur->index >= 0)
649 fprintf(output, "index %d in ", cur->index);
650 fprintf(output, "node\n");
651 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
652 depth + 1);
653 fprintf(output, shift);
654 fprintf(output, "To ");
655 if (cur->index2 >= 0)
656 fprintf(output, "index %d in ", cur->index2);
657 fprintf(output, "node\n");
658 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
659 depth + 1);
660 fprintf(output, "\n");
661 }
662 break;
663 case XPATH_LOCATIONSET:
664#if defined(LIBXML_XPTR_ENABLED)
665 fprintf(output, "Object is a Location Set:\n");
666 xmlXPathDebugDumpLocationSet(output,
667 (xmlLocationSetPtr) cur->user, depth);
668#endif
669 break;
670 case XPATH_USERS:
671 fprintf(output, "Object is user defined\n");
672 break;
673 }
674}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000675
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000676static void
677xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000678 xmlXPathStepOpPtr op, int depth) {
679 int i;
680 char shift[100];
681
682 for (i = 0;((i < depth) && (i < 25));i++)
683 shift[2 * i] = shift[2 * i + 1] = ' ';
684 shift[2 * i] = shift[2 * i + 1] = 0;
685
686 fprintf(output, shift);
687 if (op == NULL) {
688 fprintf(output, "Step is NULL\n");
689 return;
690 }
691 switch (op->op) {
692 case XPATH_OP_END:
693 fprintf(output, "END"); break;
694 case XPATH_OP_AND:
695 fprintf(output, "AND"); break;
696 case XPATH_OP_OR:
697 fprintf(output, "OR"); break;
698 case XPATH_OP_EQUAL:
699 if (op->value)
700 fprintf(output, "EQUAL =");
701 else
702 fprintf(output, "EQUAL !=");
703 break;
704 case XPATH_OP_CMP:
705 if (op->value)
706 fprintf(output, "CMP <");
707 else
708 fprintf(output, "CMP >");
709 if (!op->value2)
710 fprintf(output, "=");
711 break;
712 case XPATH_OP_PLUS:
713 if (op->value == 0)
714 fprintf(output, "PLUS -");
715 else if (op->value == 1)
716 fprintf(output, "PLUS +");
717 else if (op->value == 2)
718 fprintf(output, "PLUS unary -");
719 else if (op->value == 3)
720 fprintf(output, "PLUS unary - -");
721 break;
722 case XPATH_OP_MULT:
723 if (op->value == 0)
724 fprintf(output, "MULT *");
725 else if (op->value == 1)
726 fprintf(output, "MULT div");
727 else
728 fprintf(output, "MULT mod");
729 break;
730 case XPATH_OP_UNION:
731 fprintf(output, "UNION"); break;
732 case XPATH_OP_ROOT:
733 fprintf(output, "ROOT"); break;
734 case XPATH_OP_NODE:
735 fprintf(output, "NODE"); break;
736 case XPATH_OP_RESET:
737 fprintf(output, "RESET"); break;
738 case XPATH_OP_SORT:
739 fprintf(output, "SORT"); break;
740 case XPATH_OP_COLLECT: {
741 xmlXPathAxisVal axis = op->value;
742 xmlXPathTestVal test = op->value2;
743 xmlXPathTypeVal type = op->value3;
744 const xmlChar *prefix = op->value4;
745 const xmlChar *name = op->value5;
746
747 fprintf(output, "COLLECT ");
748 switch (axis) {
749 case AXIS_ANCESTOR:
750 fprintf(output, " 'ancestors' "); break;
751 case AXIS_ANCESTOR_OR_SELF:
752 fprintf(output, " 'ancestors-or-self' "); break;
753 case AXIS_ATTRIBUTE:
754 fprintf(output, " 'attributes' "); break;
755 case AXIS_CHILD:
756 fprintf(output, " 'child' "); break;
757 case AXIS_DESCENDANT:
758 fprintf(output, " 'descendant' "); break;
759 case AXIS_DESCENDANT_OR_SELF:
760 fprintf(output, " 'descendant-or-self' "); break;
761 case AXIS_FOLLOWING:
762 fprintf(output, " 'following' "); break;
763 case AXIS_FOLLOWING_SIBLING:
764 fprintf(output, " 'following-siblings' "); break;
765 case AXIS_NAMESPACE:
766 fprintf(output, " 'namespace' "); break;
767 case AXIS_PARENT:
768 fprintf(output, " 'parent' "); break;
769 case AXIS_PRECEDING:
770 fprintf(output, " 'preceding' "); break;
771 case AXIS_PRECEDING_SIBLING:
772 fprintf(output, " 'preceding-sibling' "); break;
773 case AXIS_SELF:
774 fprintf(output, " 'self' "); break;
775 }
776 switch (test) {
777 case NODE_TEST_NONE:
778 fprintf(output, "'none' "); break;
779 case NODE_TEST_TYPE:
780 fprintf(output, "'type' "); break;
781 case NODE_TEST_PI:
782 fprintf(output, "'PI' "); break;
783 case NODE_TEST_ALL:
784 fprintf(output, "'all' "); break;
785 case NODE_TEST_NS:
786 fprintf(output, "'namespace' "); break;
787 case NODE_TEST_NAME:
788 fprintf(output, "'name' "); break;
789 }
790 switch (type) {
791 case NODE_TYPE_NODE:
792 fprintf(output, "'node' "); break;
793 case NODE_TYPE_COMMENT:
794 fprintf(output, "'comment' "); break;
795 case NODE_TYPE_TEXT:
796 fprintf(output, "'text' "); break;
797 case NODE_TYPE_PI:
798 fprintf(output, "'PI' "); break;
799 }
800 if (prefix != NULL)
801 fprintf(output, "%s:", prefix);
802 if (name != NULL)
803 fprintf(output, "%s", name);
804 break;
805
806 }
807 case XPATH_OP_VALUE: {
808 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
809
810 fprintf(output, "ELEM ");
811 xmlXPathDebugDumpObject(output, object, 0);
812 goto finish;
813 }
814 case XPATH_OP_VARIABLE: {
815 const xmlChar *prefix = op->value5;
816 const xmlChar *name = op->value4;
817
818 if (prefix != NULL)
819 fprintf(output, "VARIABLE %s:%s", prefix, name);
820 else
821 fprintf(output, "VARIABLE %s", name);
822 break;
823 }
824 case XPATH_OP_FUNCTION: {
825 int nbargs = op->value;
826 const xmlChar *prefix = op->value5;
827 const xmlChar *name = op->value4;
828
829 if (prefix != NULL)
830 fprintf(output, "FUNCTION %s:%s(%d args)",
831 prefix, name, nbargs);
832 else
833 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
834 break;
835 }
836 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
837 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000838 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +0000839#ifdef LIBXML_XPTR_ENABLED
840 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
841#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000842 default:
843 fprintf(output, "UNKNOWN %d\n", op->op); return;
844 }
845 fprintf(output, "\n");
846finish:
847 if (op->ch1 >= 0)
848 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
849 if (op->ch2 >= 0)
850 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
851}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000852
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000853/**
854 * xmlXPathDebugDumpCompExpr:
855 * @output: the FILE * for the output
856 * @comp: the precompiled XPath expression
857 * @depth: the indentation level.
858 *
859 * Dumps the tree of the compiled XPath expression.
860 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000861void
862xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
863 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000864 int i;
865 char shift[100];
866
867 for (i = 0;((i < depth) && (i < 25));i++)
868 shift[2 * i] = shift[2 * i + 1] = ' ';
869 shift[2 * i] = shift[2 * i + 1] = 0;
870
871 fprintf(output, shift);
872
873 if (comp == NULL) {
874 fprintf(output, "Compiled Expression is NULL\n");
875 return;
876 }
877 fprintf(output, "Compiled Expression : %d elements\n",
878 comp->nbStep);
879 i = comp->last;
880 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
881}
Daniel Veillard017b1082001-06-21 11:20:21 +0000882#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000883
884/************************************************************************
885 * *
886 * Parser stacks related functions and macros *
887 * *
888 ************************************************************************/
889
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000890/**
891 * valuePop:
892 * @ctxt: an XPath evaluation context
893 *
894 * Pops the top XPath object from the value stack
895 *
896 * Returns the XPath object just removed
897 */
Daniel Veillard1c732d22002-11-30 11:22:59 +0000898extern xmlXPathObjectPtr
899valuePop(xmlXPathParserContextPtr ctxt)
900{
901 xmlXPathObjectPtr ret;
902
903 if (ctxt->valueNr <= 0)
904 return (0);
905 ctxt->valueNr--;
906 if (ctxt->valueNr > 0)
907 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
908 else
909 ctxt->value = NULL;
910 ret = ctxt->valueTab[ctxt->valueNr];
911 ctxt->valueTab[ctxt->valueNr] = 0;
912 return (ret);
913}
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000914/**
915 * valuePush:
916 * @ctxt: an XPath evaluation context
917 * @value: the XPath object
918 *
919 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000920 *
921 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000922 */
Daniel Veillard1c732d22002-11-30 11:22:59 +0000923extern int
924valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
925{
926 if (ctxt->valueNr >= ctxt->valueMax) {
927 ctxt->valueMax *= 2;
928 ctxt->valueTab =
929 (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
930 ctxt->valueMax *
931 sizeof(ctxt->valueTab[0]));
932 if (ctxt->valueTab == NULL) {
933 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
934 return (0);
935 }
936 }
937 ctxt->valueTab[ctxt->valueNr] = value;
938 ctxt->value = value;
939 return (ctxt->valueNr++);
940}
Owen Taylor3473f882001-02-23 17:55:21 +0000941
Thomas Broyerf06a3d82001-07-16 04:52:57 +0000942/**
943 * xmlXPathPopBoolean:
944 * @ctxt: an XPath parser context
945 *
946 * Pops a boolean from the stack, handling conversion if needed.
947 * Check error with #xmlXPathCheckError.
948 *
949 * Returns the boolean
950 */
951int
952xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
953 xmlXPathObjectPtr obj;
954 int ret;
955
956 obj = valuePop(ctxt);
957 if (obj == NULL) {
958 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
959 return(0);
960 }
961 ret = xmlXPathCastToBoolean(obj);
962 xmlXPathFreeObject(obj);
963 return(ret);
964}
965
966/**
967 * xmlXPathPopNumber:
968 * @ctxt: an XPath parser context
969 *
970 * Pops a number from the stack, handling conversion if needed.
971 * Check error with #xmlXPathCheckError.
972 *
973 * Returns the number
974 */
975double
976xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
977 xmlXPathObjectPtr obj;
978 double ret;
979
980 obj = valuePop(ctxt);
981 if (obj == NULL) {
982 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
983 return(0);
984 }
985 ret = xmlXPathCastToNumber(obj);
986 xmlXPathFreeObject(obj);
987 return(ret);
988}
989
990/**
991 * xmlXPathPopString:
992 * @ctxt: an XPath parser context
993 *
994 * Pops a string from the stack, handling conversion if needed.
995 * Check error with #xmlXPathCheckError.
996 *
997 * Returns the string
998 */
999xmlChar *
1000xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
1001 xmlXPathObjectPtr obj;
1002 xmlChar * ret;
1003
1004 obj = valuePop(ctxt);
1005 if (obj == NULL) {
1006 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1007 return(NULL);
1008 }
1009 ret = xmlXPathCastToString(obj);
1010 /* TODO: needs refactoring somewhere else */
1011 if (obj->stringval == ret)
1012 obj->stringval = NULL;
1013 xmlXPathFreeObject(obj);
1014 return(ret);
1015}
1016
1017/**
1018 * xmlXPathPopNodeSet:
1019 * @ctxt: an XPath parser context
1020 *
1021 * Pops a node-set from the stack, handling conversion if needed.
1022 * Check error with #xmlXPathCheckError.
1023 *
1024 * Returns the node-set
1025 */
1026xmlNodeSetPtr
1027xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
1028 xmlXPathObjectPtr obj;
1029 xmlNodeSetPtr ret;
1030
1031 if (ctxt->value == NULL) {
1032 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1033 return(NULL);
1034 }
1035 if (!xmlXPathStackIsNodeSet(ctxt)) {
1036 xmlXPathSetTypeError(ctxt);
1037 return(NULL);
1038 }
1039 obj = valuePop(ctxt);
1040 ret = obj->nodesetval;
1041 xmlXPathFreeNodeSetList(obj);
1042 return(ret);
1043}
1044
1045/**
1046 * xmlXPathPopExternal:
1047 * @ctxt: an XPath parser context
1048 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001049 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001050 * Check error with #xmlXPathCheckError.
1051 *
1052 * Returns the object
1053 */
1054void *
1055xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1056 xmlXPathObjectPtr obj;
1057 void * ret;
1058
1059 if (ctxt->value == NULL) {
1060 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1061 return(NULL);
1062 }
1063 if (ctxt->value->type != XPATH_USERS) {
1064 xmlXPathSetTypeError(ctxt);
1065 return(NULL);
1066 }
1067 obj = valuePop(ctxt);
1068 ret = obj->user;
1069 xmlXPathFreeObject(obj);
1070 return(ret);
1071}
1072
Owen Taylor3473f882001-02-23 17:55:21 +00001073/*
1074 * Macros for accessing the content. Those should be used only by the parser,
1075 * and not exported.
1076 *
1077 * Dirty macros, i.e. one need to make assumption on the context to use them
1078 *
1079 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1080 * CUR returns the current xmlChar value, i.e. a 8 bit value
1081 * in ISO-Latin or UTF-8.
1082 * This should be used internally by the parser
1083 * only to compare to ASCII values otherwise it would break when
1084 * running with UTF-8 encoding.
1085 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1086 * to compare on ASCII based substring.
1087 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1088 * strings within the parser.
1089 * CURRENT Returns the current char value, with the full decoding of
1090 * UTF-8 if we are using this mode. It returns an int.
1091 * NEXT Skip to the next character, this does the proper decoding
1092 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1093 * It returns the pointer to the current xmlChar.
1094 */
1095
1096#define CUR (*ctxt->cur)
1097#define SKIP(val) ctxt->cur += (val)
1098#define NXT(val) ctxt->cur[(val)]
1099#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001100#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1101
1102#define COPY_BUF(l,b,i,v) \
1103 if (l == 1) b[i++] = (xmlChar) v; \
1104 else i += xmlCopyChar(l,&b[i],v)
1105
1106#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001107
1108#define SKIP_BLANKS \
1109 while (IS_BLANK(*(ctxt->cur))) NEXT
1110
1111#define CURRENT (*ctxt->cur)
1112#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1113
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001114
1115#ifndef DBL_DIG
1116#define DBL_DIG 16
1117#endif
1118#ifndef DBL_EPSILON
1119#define DBL_EPSILON 1E-9
1120#endif
1121
1122#define UPPER_DOUBLE 1E9
1123#define LOWER_DOUBLE 1E-5
1124
1125#define INTEGER_DIGITS DBL_DIG
1126#define FRACTION_DIGITS (DBL_DIG + 1)
1127#define EXPONENT_DIGITS (3 + 2)
1128
1129/**
1130 * xmlXPathFormatNumber:
1131 * @number: number to format
1132 * @buffer: output buffer
1133 * @buffersize: size of output buffer
1134 *
1135 * Convert the number into a string representation.
1136 */
1137static void
1138xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1139{
Daniel Veillardcda96922001-08-21 10:56:31 +00001140 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001141 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001142 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001143 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001144 break;
1145 case -1:
1146 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001147 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001148 break;
1149 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001150 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001151 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001152 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001153 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001154 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001155 } else if (number == ((int) number)) {
1156 char work[30];
1157 char *ptr, *cur;
1158 int res, value = (int) number;
1159
1160 ptr = &buffer[0];
1161 if (value < 0) {
1162 *ptr++ = '-';
1163 value = -value;
1164 }
1165 if (value == 0) {
1166 *ptr++ = '0';
1167 } else {
1168 cur = &work[0];
1169 while (value != 0) {
1170 res = value % 10;
1171 value = value / 10;
1172 *cur++ = '0' + res;
1173 }
1174 cur--;
1175 while ((cur >= &work[0]) && (ptr - buffer < buffersize)) {
1176 *ptr++ = *cur--;
1177 }
1178 }
1179 if (ptr - buffer < buffersize) {
1180 *ptr = 0;
1181 } else if (buffersize > 0) {
1182 ptr--;
1183 *ptr = 0;
1184 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001185 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001186 /* 3 is sign, decimal point, and terminating zero */
1187 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1188 int integer_place, fraction_place;
1189 char *ptr;
1190 char *after_fraction;
1191 double absolute_value;
1192 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001193
Bjorn Reese70a9da52001-04-21 16:57:29 +00001194 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001195
Bjorn Reese70a9da52001-04-21 16:57:29 +00001196 /*
1197 * First choose format - scientific or regular floating point.
1198 * In either case, result is in work, and after_fraction points
1199 * just past the fractional part.
1200 */
1201 if ( ((absolute_value > UPPER_DOUBLE) ||
1202 (absolute_value < LOWER_DOUBLE)) &&
1203 (absolute_value != 0.0) ) {
1204 /* Use scientific notation */
1205 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1206 fraction_place = DBL_DIG - 1;
1207 snprintf(work, sizeof(work),"%*.*e",
1208 integer_place, fraction_place, number);
1209 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001210 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001211 else {
1212 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001213 if (absolute_value > 0.0)
1214 integer_place = 1 + (int)log10(absolute_value);
1215 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001216 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001217 fraction_place = (integer_place > 0)
1218 ? DBL_DIG - integer_place
1219 : DBL_DIG;
1220 size = snprintf(work, sizeof(work), "%0.*f",
1221 fraction_place, number);
1222 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001223 }
1224
Bjorn Reese70a9da52001-04-21 16:57:29 +00001225 /* Remove fractional trailing zeroes */
1226 ptr = after_fraction;
1227 while (*(--ptr) == '0')
1228 ;
1229 if (*ptr != '.')
1230 ptr++;
1231 strcpy(ptr, after_fraction);
1232
1233 /* Finally copy result back to caller */
1234 size = strlen(work) + 1;
1235 if (size > buffersize) {
1236 work[buffersize - 1] = 0;
1237 size = buffersize;
1238 }
1239 memcpy(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001240 }
1241 break;
1242 }
1243}
1244
Owen Taylor3473f882001-02-23 17:55:21 +00001245/************************************************************************
1246 * *
1247 * Error handling routines *
1248 * *
1249 ************************************************************************/
1250
1251
Daniel Veillardb44025c2001-10-11 22:55:55 +00001252static const char *xmlXPathErrorMessages[] = {
Owen Taylor3473f882001-02-23 17:55:21 +00001253 "Ok",
1254 "Number encoding",
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001255 "Unfinished literal",
1256 "Start of literal",
Owen Taylor3473f882001-02-23 17:55:21 +00001257 "Expected $ for variable reference",
1258 "Undefined variable",
1259 "Invalid predicate",
1260 "Invalid expression",
1261 "Missing closing curly brace",
1262 "Unregistered function",
1263 "Invalid operand",
1264 "Invalid type",
1265 "Invalid number of arguments",
1266 "Invalid context size",
1267 "Invalid context position",
1268 "Memory allocation error",
1269 "Syntax error",
1270 "Resource error",
1271 "Sub resource error",
Daniel Veillard61d80a22001-04-27 17:13:01 +00001272 "Undefined namespace prefix",
1273 "Encoding error",
1274 "Char out of XML range"
Owen Taylor3473f882001-02-23 17:55:21 +00001275};
1276
1277/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001278 * xmlXPatherror:
Owen Taylor3473f882001-02-23 17:55:21 +00001279 * @ctxt: the XPath Parser context
1280 * @file: the file name
1281 * @line: the line number
1282 * @no: the error number
1283 *
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001284 * Formats an error message.
Owen Taylor3473f882001-02-23 17:55:21 +00001285 */
1286void
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00001287xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
1288 int line ATTRIBUTE_UNUSED, int no) {
Owen Taylor3473f882001-02-23 17:55:21 +00001289 int n;
1290 const xmlChar *cur;
1291 const xmlChar *base;
1292
Owen Taylor3473f882001-02-23 17:55:21 +00001293 cur = ctxt->cur;
1294 base = ctxt->base;
Daniel Veillard118aed72002-09-24 14:13:13 +00001295 if ((cur == NULL) || (base == NULL)) {
1296 if ((ctxt->comp != NULL) && (ctxt->comp->expr != NULL)) {
1297 xmlGenericError(xmlGenericErrorContext,
1298 "XPath error %s in %s\n", xmlXPathErrorMessages[no],
1299 ctxt->comp->expr);
1300 } else {
1301 xmlGenericError(xmlGenericErrorContext,
1302 "XPath error %s\n", xmlXPathErrorMessages[no]);
1303 }
1304
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001305 return;
Daniel Veillard118aed72002-09-24 14:13:13 +00001306 }
1307 xmlGenericError(xmlGenericErrorContext,
1308 "XPath error %s\n", xmlXPathErrorMessages[no]);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001309
Owen Taylor3473f882001-02-23 17:55:21 +00001310 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
1311 cur--;
1312 }
1313 n = 0;
1314 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
1315 cur--;
1316 if ((*cur == '\n') || (*cur == '\r')) cur++;
1317 base = cur;
1318 n = 0;
1319 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
1320 xmlGenericError(xmlGenericErrorContext, "%c", (unsigned char) *cur++);
1321 n++;
1322 }
1323 xmlGenericError(xmlGenericErrorContext, "\n");
1324 cur = ctxt->cur;
1325 while ((*cur == '\n') || (*cur == '\r'))
1326 cur--;
1327 n = 0;
1328 while ((cur != base) && (n++ < 80)) {
1329 xmlGenericError(xmlGenericErrorContext, " ");
1330 base++;
1331 }
1332 xmlGenericError(xmlGenericErrorContext,"^\n");
1333}
1334
1335
1336/************************************************************************
1337 * *
1338 * Routines to handle NodeSets *
1339 * *
1340 ************************************************************************/
1341
1342/**
1343 * xmlXPathCmpNodes:
1344 * @node1: the first node
1345 * @node2: the second node
1346 *
1347 * Compare two nodes w.r.t document order
1348 *
1349 * Returns -2 in case of error 1 if first point < second point, 0 if
1350 * that's the same node, -1 otherwise
1351 */
1352int
1353xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1354 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001355 int attr1 = 0, attr2 = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001356 xmlNodePtr cur, root;
1357
1358 if ((node1 == NULL) || (node2 == NULL))
1359 return(-2);
1360 /*
1361 * a couple of optimizations which will avoid computations in most cases
1362 */
Daniel Veillardedfd5882003-03-07 14:20:40 +00001363 if (node1->type == XML_ATTRIBUTE_NODE) {
1364 attr1 = 1;
1365 node1 = node1->parent;
1366 }
1367 if (node2->type == XML_ATTRIBUTE_NODE) {
1368 attr2 = 1;
1369 node2 = node2->parent;
1370 }
1371 if (node1 == node2) {
1372 if (attr1 == attr2)
1373 return(0);
1374 if (attr2 == 1)
1375 return(1);
1376 return(-1);
1377 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00001378 if ((node1->type == XML_NAMESPACE_DECL) ||
1379 (node2->type == XML_NAMESPACE_DECL))
1380 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001381 if (node1 == node2->prev)
1382 return(1);
1383 if (node1 == node2->next)
1384 return(-1);
1385
Daniel Veillard68e9e742002-11-16 15:35:11 +00001386#if 0
1387 Unfortunately this does not work. Line number in entities reset
1388 to 1 within the entity :-(
1389
Owen Taylor3473f882001-02-23 17:55:21 +00001390 /*
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001391 * Speedup using line numbers if availble.
1392 */
1393 if ((node1->type == XML_ELEMENT_NODE) &&
1394 (node2->type == XML_ELEMENT_NODE) &&
1395 (0 != (int) node1->content) && (0 != (int) node2->content)) {
1396 int l1, l2;
1397 l1 = (int) node1->content;
1398 l2 = (int) node2->content;
1399 if (l1 < l2)
1400 return(1);
1401 if (l1 > l2)
1402 return(-1);
1403 }
Daniel Veillard68e9e742002-11-16 15:35:11 +00001404#endif
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001405 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001406 * compute depth to root
1407 */
1408 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1409 if (cur == node1)
1410 return(1);
1411 depth2++;
1412 }
1413 root = cur;
1414 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1415 if (cur == node2)
1416 return(-1);
1417 depth1++;
1418 }
1419 /*
1420 * Distinct document (or distinct entities :-( ) case.
1421 */
1422 if (root != cur) {
1423 return(-2);
1424 }
1425 /*
1426 * get the nearest common ancestor.
1427 */
1428 while (depth1 > depth2) {
1429 depth1--;
1430 node1 = node1->parent;
1431 }
1432 while (depth2 > depth1) {
1433 depth2--;
1434 node2 = node2->parent;
1435 }
1436 while (node1->parent != node2->parent) {
1437 node1 = node1->parent;
1438 node2 = node2->parent;
1439 /* should not happen but just in case ... */
1440 if ((node1 == NULL) || (node2 == NULL))
1441 return(-2);
1442 }
1443 /*
1444 * Find who's first.
1445 */
1446 if (node1 == node2->next)
1447 return(-1);
1448 for (cur = node1->next;cur != NULL;cur = cur->next)
1449 if (cur == node2)
1450 return(1);
1451 return(-1); /* assume there is no sibling list corruption */
1452}
1453
1454/**
1455 * xmlXPathNodeSetSort:
1456 * @set: the node set
1457 *
1458 * Sort the node set in document order
1459 */
1460void
1461xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001462 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001463 xmlNodePtr tmp;
1464
1465 if (set == NULL)
1466 return;
1467
1468 /* Use Shell's sort to sort the node-set */
1469 len = set->nodeNr;
1470 for (incr = len / 2; incr > 0; incr /= 2) {
1471 for (i = incr; i < len; i++) {
1472 j = i - incr;
1473 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001474 if (xmlXPathCmpNodes(set->nodeTab[j],
1475 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001476 tmp = set->nodeTab[j];
1477 set->nodeTab[j] = set->nodeTab[j + incr];
1478 set->nodeTab[j + incr] = tmp;
1479 j -= incr;
1480 } else
1481 break;
1482 }
1483 }
1484 }
1485}
1486
1487#define XML_NODESET_DEFAULT 10
1488/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001489 * xmlXPathNodeSetDupNs:
1490 * @node: the parent node of the namespace XPath node
1491 * @ns: the libxml namespace declaration node.
1492 *
1493 * Namespace node in libxml don't match the XPath semantic. In a node set
1494 * the namespace nodes are duplicated and the next pointer is set to the
1495 * parent node in the XPath semantic.
1496 *
1497 * Returns the newly created object.
1498 */
1499static xmlNodePtr
1500xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
1501 xmlNsPtr cur;
1502
1503 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1504 return(NULL);
1505 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
1506 return((xmlNodePtr) ns);
1507
1508 /*
1509 * Allocate a new Namespace and fill the fields.
1510 */
1511 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1512 if (cur == NULL) {
1513 xmlGenericError(xmlGenericErrorContext,
1514 "xmlXPathNodeSetDupNs : malloc failed\n");
1515 return(NULL);
1516 }
1517 memset(cur, 0, sizeof(xmlNs));
1518 cur->type = XML_NAMESPACE_DECL;
1519 if (ns->href != NULL)
1520 cur->href = xmlStrdup(ns->href);
1521 if (ns->prefix != NULL)
1522 cur->prefix = xmlStrdup(ns->prefix);
1523 cur->next = (xmlNsPtr) node;
1524 return((xmlNodePtr) cur);
1525}
1526
1527/**
1528 * xmlXPathNodeSetFreeNs:
1529 * @ns: the XPath namespace node found in a nodeset.
1530 *
1531 * Namespace node in libxml don't match the XPath semantic. In a node set
1532 * the namespace nodes are duplicated and the next pointer is set to the
1533 * parent node in the XPath semantic. Check if such a node need to be freed
1534 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001535void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001536xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
1537 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1538 return;
1539
1540 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
1541 if (ns->href != NULL)
1542 xmlFree((xmlChar *)ns->href);
1543 if (ns->prefix != NULL)
1544 xmlFree((xmlChar *)ns->prefix);
1545 xmlFree(ns);
1546 }
1547}
1548
1549/**
Owen Taylor3473f882001-02-23 17:55:21 +00001550 * xmlXPathNodeSetCreate:
1551 * @val: an initial xmlNodePtr, or NULL
1552 *
1553 * Create a new xmlNodeSetPtr of type double and of value @val
1554 *
1555 * Returns the newly created object.
1556 */
1557xmlNodeSetPtr
1558xmlXPathNodeSetCreate(xmlNodePtr val) {
1559 xmlNodeSetPtr ret;
1560
1561 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1562 if (ret == NULL) {
1563 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001564 "xmlXPathNodeSetCreate: out of memory\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001565 return(NULL);
1566 }
1567 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1568 if (val != NULL) {
1569 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1570 sizeof(xmlNodePtr));
1571 if (ret->nodeTab == NULL) {
1572 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001573 "xmlXPathNodeSetCreate: out of memory\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001574 return(NULL);
1575 }
1576 memset(ret->nodeTab, 0 ,
1577 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1578 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001579 if (val->type == XML_NAMESPACE_DECL) {
1580 xmlNsPtr ns = (xmlNsPtr) val;
1581
1582 ret->nodeTab[ret->nodeNr++] =
1583 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1584 } else
1585 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001586 }
1587 return(ret);
1588}
1589
1590/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001591 * xmlXPathNodeSetContains:
1592 * @cur: the node-set
1593 * @val: the node
1594 *
1595 * checks whether @cur contains @val
1596 *
1597 * Returns true (1) if @cur contains @val, false (0) otherwise
1598 */
1599int
1600xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1601 int i;
1602
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001603 if (val->type == XML_NAMESPACE_DECL) {
1604 for (i = 0; i < cur->nodeNr; i++) {
1605 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1606 xmlNsPtr ns1, ns2;
1607
1608 ns1 = (xmlNsPtr) val;
1609 ns2 = (xmlNsPtr) cur->nodeTab[i];
1610 if (ns1 == ns2)
1611 return(1);
1612 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
1613 (xmlStrEqual(ns1->prefix, ns2->prefix)))
1614 return(1);
1615 }
1616 }
1617 } else {
1618 for (i = 0; i < cur->nodeNr; i++) {
1619 if (cur->nodeTab[i] == val)
1620 return(1);
1621 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001622 }
1623 return(0);
1624}
1625
1626/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001627 * xmlXPathNodeSetAddNs:
1628 * @cur: the initial node set
1629 * @node: the hosting node
1630 * @ns: a the namespace node
1631 *
1632 * add a new namespace node to an existing NodeSet
1633 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00001634void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001635xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
1636 int i;
1637
1638 if ((ns == NULL) || (node == NULL) || (ns->type != XML_NAMESPACE_DECL) ||
1639 (node->type != XML_ELEMENT_NODE))
1640 return;
1641
1642 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1643 /*
1644 * check against doublons
1645 */
1646 for (i = 0;i < cur->nodeNr;i++) {
1647 if ((cur->nodeTab[i] != NULL) &&
1648 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00001649 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001650 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
1651 return;
1652 }
1653
1654 /*
1655 * grow the nodeTab if needed
1656 */
1657 if (cur->nodeMax == 0) {
1658 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1659 sizeof(xmlNodePtr));
1660 if (cur->nodeTab == NULL) {
1661 xmlGenericError(xmlGenericErrorContext,
1662 "xmlXPathNodeSetAdd: out of memory\n");
1663 return;
1664 }
1665 memset(cur->nodeTab, 0 ,
1666 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1667 cur->nodeMax = XML_NODESET_DEFAULT;
1668 } else if (cur->nodeNr == cur->nodeMax) {
1669 xmlNodePtr *temp;
1670
1671 cur->nodeMax *= 2;
1672 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1673 sizeof(xmlNodePtr));
1674 if (temp == NULL) {
1675 xmlGenericError(xmlGenericErrorContext,
1676 "xmlXPathNodeSetAdd: out of memory\n");
1677 return;
1678 }
1679 cur->nodeTab = temp;
1680 }
1681 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
1682}
1683
1684/**
Owen Taylor3473f882001-02-23 17:55:21 +00001685 * xmlXPathNodeSetAdd:
1686 * @cur: the initial node set
1687 * @val: a new xmlNodePtr
1688 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001689 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00001690 */
1691void
1692xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1693 int i;
1694
1695 if (val == NULL) return;
1696
Daniel Veillard652d8a92003-02-04 19:28:49 +00001697 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1698 return; /* an XSLT fake node */
1699
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001700 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001701 /*
1702 * check against doublons
1703 */
1704 for (i = 0;i < cur->nodeNr;i++)
1705 if (cur->nodeTab[i] == val) return;
1706
1707 /*
1708 * grow the nodeTab if needed
1709 */
1710 if (cur->nodeMax == 0) {
1711 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1712 sizeof(xmlNodePtr));
1713 if (cur->nodeTab == NULL) {
1714 xmlGenericError(xmlGenericErrorContext,
1715 "xmlXPathNodeSetAdd: out of memory\n");
1716 return;
1717 }
1718 memset(cur->nodeTab, 0 ,
1719 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1720 cur->nodeMax = XML_NODESET_DEFAULT;
1721 } else if (cur->nodeNr == cur->nodeMax) {
1722 xmlNodePtr *temp;
1723
1724 cur->nodeMax *= 2;
1725 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1726 sizeof(xmlNodePtr));
1727 if (temp == NULL) {
1728 xmlGenericError(xmlGenericErrorContext,
1729 "xmlXPathNodeSetAdd: out of memory\n");
1730 return;
1731 }
1732 cur->nodeTab = temp;
1733 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001734 if (val->type == XML_NAMESPACE_DECL) {
1735 xmlNsPtr ns = (xmlNsPtr) val;
1736
1737 cur->nodeTab[cur->nodeNr++] =
1738 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1739 } else
1740 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001741}
1742
1743/**
1744 * xmlXPathNodeSetAddUnique:
1745 * @cur: the initial node set
1746 * @val: a new xmlNodePtr
1747 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001748 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00001749 * when we are sure the node is not already in the set.
1750 */
1751void
1752xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1753 if (val == NULL) return;
1754
Daniel Veillard652d8a92003-02-04 19:28:49 +00001755 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1756 return; /* an XSLT fake node */
1757
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001758 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001759 /*
1760 * grow the nodeTab if needed
1761 */
1762 if (cur->nodeMax == 0) {
1763 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1764 sizeof(xmlNodePtr));
1765 if (cur->nodeTab == NULL) {
1766 xmlGenericError(xmlGenericErrorContext,
1767 "xmlXPathNodeSetAddUnique: out of memory\n");
1768 return;
1769 }
1770 memset(cur->nodeTab, 0 ,
1771 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1772 cur->nodeMax = XML_NODESET_DEFAULT;
1773 } else if (cur->nodeNr == cur->nodeMax) {
1774 xmlNodePtr *temp;
1775
1776 cur->nodeMax *= 2;
1777 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1778 sizeof(xmlNodePtr));
1779 if (temp == NULL) {
1780 xmlGenericError(xmlGenericErrorContext,
1781 "xmlXPathNodeSetAddUnique: out of memory\n");
1782 return;
1783 }
1784 cur->nodeTab = temp;
1785 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001786 if (val->type == XML_NAMESPACE_DECL) {
1787 xmlNsPtr ns = (xmlNsPtr) val;
1788
1789 cur->nodeTab[cur->nodeNr++] =
1790 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1791 } else
1792 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001793}
1794
1795/**
1796 * xmlXPathNodeSetMerge:
1797 * @val1: the first NodeSet or NULL
1798 * @val2: the second NodeSet
1799 *
1800 * Merges two nodesets, all nodes from @val2 are added to @val1
1801 * if @val1 is NULL, a new set is created and copied from @val2
1802 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001803 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00001804 */
1805xmlNodeSetPtr
1806xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001807 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001808
1809 if (val2 == NULL) return(val1);
1810 if (val1 == NULL) {
1811 val1 = xmlXPathNodeSetCreate(NULL);
1812 }
1813
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001814 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001815 initNr = val1->nodeNr;
1816
1817 for (i = 0;i < val2->nodeNr;i++) {
1818 /*
1819 * check against doublons
1820 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001821 skip = 0;
1822 for (j = 0; j < initNr; j++) {
1823 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1824 skip = 1;
1825 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001826 } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) &&
1827 (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) {
1828 xmlNsPtr ns1, ns2;
1829 ns1 = (xmlNsPtr) val1->nodeTab[j];
1830 ns2 = (xmlNsPtr) val2->nodeTab[i];
1831 if ((ns1->next == ns2->next) &&
1832 (xmlStrEqual(ns1->prefix, ns2->prefix))) {
1833 skip = 1;
1834 break;
1835 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001836 }
1837 }
1838 if (skip)
1839 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00001840
1841 /*
1842 * grow the nodeTab if needed
1843 */
1844 if (val1->nodeMax == 0) {
1845 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1846 sizeof(xmlNodePtr));
1847 if (val1->nodeTab == NULL) {
1848 xmlGenericError(xmlGenericErrorContext,
1849 "xmlXPathNodeSetMerge: out of memory\n");
1850 return(NULL);
1851 }
1852 memset(val1->nodeTab, 0 ,
1853 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1854 val1->nodeMax = XML_NODESET_DEFAULT;
1855 } else if (val1->nodeNr == val1->nodeMax) {
1856 xmlNodePtr *temp;
1857
1858 val1->nodeMax *= 2;
1859 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1860 sizeof(xmlNodePtr));
1861 if (temp == NULL) {
1862 xmlGenericError(xmlGenericErrorContext,
1863 "xmlXPathNodeSetMerge: out of memory\n");
1864 return(NULL);
1865 }
1866 val1->nodeTab = temp;
1867 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001868 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1869 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1870
1871 val1->nodeTab[val1->nodeNr++] =
1872 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1873 } else
1874 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00001875 }
1876
1877 return(val1);
1878}
1879
1880/**
Daniel Veillard75be0132002-03-13 10:03:35 +00001881 * xmlXPathNodeSetMergeUnique:
1882 * @val1: the first NodeSet or NULL
1883 * @val2: the second NodeSet
1884 *
1885 * Merges two nodesets, all nodes from @val2 are added to @val1
1886 * if @val1 is NULL, a new set is created and copied from @val2
1887 *
1888 * Returns @val1 once extended or NULL in case of error.
1889 */
1890static xmlNodeSetPtr
1891xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
1892 int i, initNr;
1893
1894 if (val2 == NULL) return(val1);
1895 if (val1 == NULL) {
1896 val1 = xmlXPathNodeSetCreate(NULL);
1897 }
1898
1899 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1900 initNr = val1->nodeNr;
1901
1902 for (i = 0;i < val2->nodeNr;i++) {
1903 /*
1904 * grow the nodeTab if needed
1905 */
1906 if (val1->nodeMax == 0) {
1907 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1908 sizeof(xmlNodePtr));
1909 if (val1->nodeTab == NULL) {
1910 xmlGenericError(xmlGenericErrorContext,
1911 "xmlXPathNodeSetMerge: out of memory\n");
1912 return(NULL);
1913 }
1914 memset(val1->nodeTab, 0 ,
1915 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1916 val1->nodeMax = XML_NODESET_DEFAULT;
1917 } else if (val1->nodeNr == val1->nodeMax) {
1918 xmlNodePtr *temp;
1919
1920 val1->nodeMax *= 2;
1921 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1922 sizeof(xmlNodePtr));
1923 if (temp == NULL) {
1924 xmlGenericError(xmlGenericErrorContext,
1925 "xmlXPathNodeSetMerge: out of memory\n");
1926 return(NULL);
1927 }
1928 val1->nodeTab = temp;
1929 }
1930 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1931 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1932
1933 val1->nodeTab[val1->nodeNr++] =
1934 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1935 } else
1936 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
1937 }
1938
1939 return(val1);
1940}
1941
1942/**
Owen Taylor3473f882001-02-23 17:55:21 +00001943 * xmlXPathNodeSetDel:
1944 * @cur: the initial node set
1945 * @val: an xmlNodePtr
1946 *
1947 * Removes an xmlNodePtr from an existing NodeSet
1948 */
1949void
1950xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
1951 int i;
1952
1953 if (cur == NULL) return;
1954 if (val == NULL) return;
1955
1956 /*
1957 * check against doublons
1958 */
1959 for (i = 0;i < cur->nodeNr;i++)
1960 if (cur->nodeTab[i] == val) break;
1961
1962 if (i >= cur->nodeNr) {
1963#ifdef DEBUG
1964 xmlGenericError(xmlGenericErrorContext,
1965 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
1966 val->name);
1967#endif
1968 return;
1969 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001970 if ((cur->nodeTab[i] != NULL) &&
1971 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
1972 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001973 cur->nodeNr--;
1974 for (;i < cur->nodeNr;i++)
1975 cur->nodeTab[i] = cur->nodeTab[i + 1];
1976 cur->nodeTab[cur->nodeNr] = NULL;
1977}
1978
1979/**
1980 * xmlXPathNodeSetRemove:
1981 * @cur: the initial node set
1982 * @val: the index to remove
1983 *
1984 * Removes an entry from an existing NodeSet list.
1985 */
1986void
1987xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
1988 if (cur == NULL) return;
1989 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001990 if ((cur->nodeTab[val] != NULL) &&
1991 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
1992 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00001993 cur->nodeNr--;
1994 for (;val < cur->nodeNr;val++)
1995 cur->nodeTab[val] = cur->nodeTab[val + 1];
1996 cur->nodeTab[cur->nodeNr] = NULL;
1997}
1998
1999/**
2000 * xmlXPathFreeNodeSet:
2001 * @obj: the xmlNodeSetPtr to free
2002 *
2003 * Free the NodeSet compound (not the actual nodes !).
2004 */
2005void
2006xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
2007 if (obj == NULL) return;
2008 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002009 int i;
2010
2011 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
2012 for (i = 0;i < obj->nodeNr;i++)
2013 if ((obj->nodeTab[i] != NULL) &&
2014 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
2015 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002016 xmlFree(obj->nodeTab);
2017 }
Owen Taylor3473f882001-02-23 17:55:21 +00002018 xmlFree(obj);
2019}
2020
2021/**
2022 * xmlXPathFreeValueTree:
2023 * @obj: the xmlNodeSetPtr to free
2024 *
2025 * Free the NodeSet compound and the actual tree, this is different
2026 * from xmlXPathFreeNodeSet()
2027 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002028static void
Owen Taylor3473f882001-02-23 17:55:21 +00002029xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
2030 int i;
2031
2032 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002033
2034 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002035 for (i = 0;i < obj->nodeNr;i++) {
2036 if (obj->nodeTab[i] != NULL) {
2037 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2038 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
2039 } else {
2040 xmlFreeNodeList(obj->nodeTab[i]);
2041 }
2042 }
2043 }
Owen Taylor3473f882001-02-23 17:55:21 +00002044 xmlFree(obj->nodeTab);
2045 }
Owen Taylor3473f882001-02-23 17:55:21 +00002046 xmlFree(obj);
2047}
2048
2049#if defined(DEBUG) || defined(DEBUG_STEP)
2050/**
2051 * xmlGenericErrorContextNodeSet:
2052 * @output: a FILE * for the output
2053 * @obj: the xmlNodeSetPtr to free
2054 *
2055 * Quick display of a NodeSet
2056 */
2057void
2058xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
2059 int i;
2060
2061 if (output == NULL) output = xmlGenericErrorContext;
2062 if (obj == NULL) {
2063 fprintf(output, "NodeSet == NULL !\n");
2064 return;
2065 }
2066 if (obj->nodeNr == 0) {
2067 fprintf(output, "NodeSet is empty\n");
2068 return;
2069 }
2070 if (obj->nodeTab == NULL) {
2071 fprintf(output, " nodeTab == NULL !\n");
2072 return;
2073 }
2074 for (i = 0; i < obj->nodeNr; i++) {
2075 if (obj->nodeTab[i] == NULL) {
2076 fprintf(output, " NULL !\n");
2077 return;
2078 }
2079 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
2080 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
2081 fprintf(output, " /");
2082 else if (obj->nodeTab[i]->name == NULL)
2083 fprintf(output, " noname!");
2084 else fprintf(output, " %s", obj->nodeTab[i]->name);
2085 }
2086 fprintf(output, "\n");
2087}
2088#endif
2089
2090/**
2091 * xmlXPathNewNodeSet:
2092 * @val: the NodePtr value
2093 *
2094 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2095 * it with the single Node @val
2096 *
2097 * Returns the newly created object.
2098 */
2099xmlXPathObjectPtr
2100xmlXPathNewNodeSet(xmlNodePtr val) {
2101 xmlXPathObjectPtr ret;
2102
2103 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2104 if (ret == NULL) {
2105 xmlGenericError(xmlGenericErrorContext,
2106 "xmlXPathNewNodeSet: out of memory\n");
2107 return(NULL);
2108 }
2109 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2110 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00002111 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002112 ret->nodesetval = xmlXPathNodeSetCreate(val);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002113 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002114 return(ret);
2115}
2116
2117/**
2118 * xmlXPathNewValueTree:
2119 * @val: the NodePtr value
2120 *
2121 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
2122 * it with the tree root @val
2123 *
2124 * Returns the newly created object.
2125 */
2126xmlXPathObjectPtr
2127xmlXPathNewValueTree(xmlNodePtr val) {
2128 xmlXPathObjectPtr ret;
2129
2130 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2131 if (ret == NULL) {
2132 xmlGenericError(xmlGenericErrorContext,
2133 "xmlXPathNewNodeSet: out of memory\n");
2134 return(NULL);
2135 }
2136 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2137 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002138 ret->boolval = 1;
2139 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00002140 ret->nodesetval = xmlXPathNodeSetCreate(val);
2141 return(ret);
2142}
2143
2144/**
2145 * xmlXPathNewNodeSetList:
2146 * @val: an existing NodeSet
2147 *
2148 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2149 * it with the Nodeset @val
2150 *
2151 * Returns the newly created object.
2152 */
2153xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002154xmlXPathNewNodeSetList(xmlNodeSetPtr val)
2155{
Owen Taylor3473f882001-02-23 17:55:21 +00002156 xmlXPathObjectPtr ret;
2157 int i;
2158
2159 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002160 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002161 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002162 ret = xmlXPathNewNodeSet(NULL);
2163 else {
2164 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
2165 for (i = 1; i < val->nodeNr; ++i)
2166 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2167 }
Owen Taylor3473f882001-02-23 17:55:21 +00002168
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002169 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002170}
2171
2172/**
2173 * xmlXPathWrapNodeSet:
2174 * @val: the NodePtr value
2175 *
2176 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2177 *
2178 * Returns the newly created object.
2179 */
2180xmlXPathObjectPtr
2181xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2182 xmlXPathObjectPtr ret;
2183
2184 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2185 if (ret == NULL) {
2186 xmlGenericError(xmlGenericErrorContext,
2187 "xmlXPathWrapNodeSet: out of memory\n");
2188 return(NULL);
2189 }
2190 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2191 ret->type = XPATH_NODESET;
2192 ret->nodesetval = val;
2193 return(ret);
2194}
2195
2196/**
2197 * xmlXPathFreeNodeSetList:
2198 * @obj: an existing NodeSetList object
2199 *
2200 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2201 * the list contrary to xmlXPathFreeObject().
2202 */
2203void
2204xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2205 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002206 xmlFree(obj);
2207}
2208
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002209/**
2210 * xmlXPathDifference:
2211 * @nodes1: a node-set
2212 * @nodes2: a node-set
2213 *
2214 * Implements the EXSLT - Sets difference() function:
2215 * node-set set:difference (node-set, node-set)
2216 *
2217 * Returns the difference between the two node sets, or nodes1 if
2218 * nodes2 is empty
2219 */
2220xmlNodeSetPtr
2221xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2222 xmlNodeSetPtr ret;
2223 int i, l1;
2224 xmlNodePtr cur;
2225
2226 if (xmlXPathNodeSetIsEmpty(nodes2))
2227 return(nodes1);
2228
2229 ret = xmlXPathNodeSetCreate(NULL);
2230 if (xmlXPathNodeSetIsEmpty(nodes1))
2231 return(ret);
2232
2233 l1 = xmlXPathNodeSetGetLength(nodes1);
2234
2235 for (i = 0; i < l1; i++) {
2236 cur = xmlXPathNodeSetItem(nodes1, i);
2237 if (!xmlXPathNodeSetContains(nodes2, cur))
2238 xmlXPathNodeSetAddUnique(ret, cur);
2239 }
2240 return(ret);
2241}
2242
2243/**
2244 * xmlXPathIntersection:
2245 * @nodes1: a node-set
2246 * @nodes2: a node-set
2247 *
2248 * Implements the EXSLT - Sets intersection() function:
2249 * node-set set:intersection (node-set, node-set)
2250 *
2251 * Returns a node set comprising the nodes that are within both the
2252 * node sets passed as arguments
2253 */
2254xmlNodeSetPtr
2255xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2256 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2257 int i, l1;
2258 xmlNodePtr cur;
2259
2260 if (xmlXPathNodeSetIsEmpty(nodes1))
2261 return(ret);
2262 if (xmlXPathNodeSetIsEmpty(nodes2))
2263 return(ret);
2264
2265 l1 = xmlXPathNodeSetGetLength(nodes1);
2266
2267 for (i = 0; i < l1; i++) {
2268 cur = xmlXPathNodeSetItem(nodes1, i);
2269 if (xmlXPathNodeSetContains(nodes2, cur))
2270 xmlXPathNodeSetAddUnique(ret, cur);
2271 }
2272 return(ret);
2273}
2274
2275/**
2276 * xmlXPathDistinctSorted:
2277 * @nodes: a node-set, sorted by document order
2278 *
2279 * Implements the EXSLT - Sets distinct() function:
2280 * node-set set:distinct (node-set)
2281 *
2282 * Returns a subset of the nodes contained in @nodes, or @nodes if
2283 * it is empty
2284 */
2285xmlNodeSetPtr
2286xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2287 xmlNodeSetPtr ret;
2288 xmlHashTablePtr hash;
2289 int i, l;
2290 xmlChar * strval;
2291 xmlNodePtr cur;
2292
2293 if (xmlXPathNodeSetIsEmpty(nodes))
2294 return(nodes);
2295
2296 ret = xmlXPathNodeSetCreate(NULL);
2297 l = xmlXPathNodeSetGetLength(nodes);
2298 hash = xmlHashCreate (l);
2299 for (i = 0; i < l; i++) {
2300 cur = xmlXPathNodeSetItem(nodes, i);
2301 strval = xmlXPathCastNodeToString(cur);
2302 if (xmlHashLookup(hash, strval) == NULL) {
2303 xmlHashAddEntry(hash, strval, strval);
2304 xmlXPathNodeSetAddUnique(ret, cur);
2305 } else {
2306 xmlFree(strval);
2307 }
2308 }
2309 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2310 return(ret);
2311}
2312
2313/**
2314 * xmlXPathDistinct:
2315 * @nodes: a node-set
2316 *
2317 * Implements the EXSLT - Sets distinct() function:
2318 * node-set set:distinct (node-set)
2319 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2320 * is called with the sorted node-set
2321 *
2322 * Returns a subset of the nodes contained in @nodes, or @nodes if
2323 * it is empty
2324 */
2325xmlNodeSetPtr
2326xmlXPathDistinct (xmlNodeSetPtr nodes) {
2327 if (xmlXPathNodeSetIsEmpty(nodes))
2328 return(nodes);
2329
2330 xmlXPathNodeSetSort(nodes);
2331 return(xmlXPathDistinctSorted(nodes));
2332}
2333
2334/**
2335 * xmlXPathHasSameNodes:
2336 * @nodes1: a node-set
2337 * @nodes2: a node-set
2338 *
2339 * Implements the EXSLT - Sets has-same-nodes function:
2340 * boolean set:has-same-node(node-set, node-set)
2341 *
2342 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2343 * otherwise
2344 */
2345int
2346xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2347 int i, l;
2348 xmlNodePtr cur;
2349
2350 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2351 xmlXPathNodeSetIsEmpty(nodes2))
2352 return(0);
2353
2354 l = xmlXPathNodeSetGetLength(nodes1);
2355 for (i = 0; i < l; i++) {
2356 cur = xmlXPathNodeSetItem(nodes1, i);
2357 if (xmlXPathNodeSetContains(nodes2, cur))
2358 return(1);
2359 }
2360 return(0);
2361}
2362
2363/**
2364 * xmlXPathNodeLeadingSorted:
2365 * @nodes: a node-set, sorted by document order
2366 * @node: a node
2367 *
2368 * Implements the EXSLT - Sets leading() function:
2369 * node-set set:leading (node-set, node-set)
2370 *
2371 * Returns the nodes in @nodes that precede @node in document order,
2372 * @nodes if @node is NULL or an empty node-set if @nodes
2373 * doesn't contain @node
2374 */
2375xmlNodeSetPtr
2376xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2377 int i, l;
2378 xmlNodePtr cur;
2379 xmlNodeSetPtr ret;
2380
2381 if (node == NULL)
2382 return(nodes);
2383
2384 ret = xmlXPathNodeSetCreate(NULL);
2385 if (xmlXPathNodeSetIsEmpty(nodes) ||
2386 (!xmlXPathNodeSetContains(nodes, node)))
2387 return(ret);
2388
2389 l = xmlXPathNodeSetGetLength(nodes);
2390 for (i = 0; i < l; i++) {
2391 cur = xmlXPathNodeSetItem(nodes, i);
2392 if (cur == node)
2393 break;
2394 xmlXPathNodeSetAddUnique(ret, cur);
2395 }
2396 return(ret);
2397}
2398
2399/**
2400 * xmlXPathNodeLeading:
2401 * @nodes: a node-set
2402 * @node: a node
2403 *
2404 * Implements the EXSLT - Sets leading() function:
2405 * node-set set:leading (node-set, node-set)
2406 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2407 * is called.
2408 *
2409 * Returns the nodes in @nodes that precede @node in document order,
2410 * @nodes if @node is NULL or an empty node-set if @nodes
2411 * doesn't contain @node
2412 */
2413xmlNodeSetPtr
2414xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2415 xmlXPathNodeSetSort(nodes);
2416 return(xmlXPathNodeLeadingSorted(nodes, node));
2417}
2418
2419/**
2420 * xmlXPathLeadingSorted:
2421 * @nodes1: a node-set, sorted by document order
2422 * @nodes2: a node-set, sorted by document order
2423 *
2424 * Implements the EXSLT - Sets leading() function:
2425 * node-set set:leading (node-set, node-set)
2426 *
2427 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2428 * in document order, @nodes1 if @nodes2 is NULL or empty or
2429 * an empty node-set if @nodes1 doesn't contain @nodes2
2430 */
2431xmlNodeSetPtr
2432xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2433 if (xmlXPathNodeSetIsEmpty(nodes2))
2434 return(nodes1);
2435 return(xmlXPathNodeLeadingSorted(nodes1,
2436 xmlXPathNodeSetItem(nodes2, 1)));
2437}
2438
2439/**
2440 * xmlXPathLeading:
2441 * @nodes1: a node-set
2442 * @nodes2: a node-set
2443 *
2444 * Implements the EXSLT - Sets leading() function:
2445 * node-set set:leading (node-set, node-set)
2446 * @nodes1 and @nodes2 are sorted by document order, then
2447 * #exslSetsLeadingSorted is called.
2448 *
2449 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2450 * in document order, @nodes1 if @nodes2 is NULL or empty or
2451 * an empty node-set if @nodes1 doesn't contain @nodes2
2452 */
2453xmlNodeSetPtr
2454xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2455 if (xmlXPathNodeSetIsEmpty(nodes2))
2456 return(nodes1);
2457 if (xmlXPathNodeSetIsEmpty(nodes1))
2458 return(xmlXPathNodeSetCreate(NULL));
2459 xmlXPathNodeSetSort(nodes1);
2460 xmlXPathNodeSetSort(nodes2);
2461 return(xmlXPathNodeLeadingSorted(nodes1,
2462 xmlXPathNodeSetItem(nodes2, 1)));
2463}
2464
2465/**
2466 * xmlXPathNodeTrailingSorted:
2467 * @nodes: a node-set, sorted by document order
2468 * @node: a node
2469 *
2470 * Implements the EXSLT - Sets trailing() function:
2471 * node-set set:trailing (node-set, node-set)
2472 *
2473 * Returns the nodes in @nodes that follow @node in document order,
2474 * @nodes if @node is NULL or an empty node-set if @nodes
2475 * doesn't contain @node
2476 */
2477xmlNodeSetPtr
2478xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2479 int i, l;
2480 xmlNodePtr cur;
2481 xmlNodeSetPtr ret;
2482
2483 if (node == NULL)
2484 return(nodes);
2485
2486 ret = xmlXPathNodeSetCreate(NULL);
2487 if (xmlXPathNodeSetIsEmpty(nodes) ||
2488 (!xmlXPathNodeSetContains(nodes, node)))
2489 return(ret);
2490
2491 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002492 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002493 cur = xmlXPathNodeSetItem(nodes, i);
2494 if (cur == node)
2495 break;
2496 xmlXPathNodeSetAddUnique(ret, cur);
2497 }
2498 return(ret);
2499}
2500
2501/**
2502 * xmlXPathNodeTrailing:
2503 * @nodes: a node-set
2504 * @node: a node
2505 *
2506 * Implements the EXSLT - Sets trailing() function:
2507 * node-set set:trailing (node-set, node-set)
2508 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2509 * is called.
2510 *
2511 * Returns the nodes in @nodes that follow @node in document order,
2512 * @nodes if @node is NULL or an empty node-set if @nodes
2513 * doesn't contain @node
2514 */
2515xmlNodeSetPtr
2516xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2517 xmlXPathNodeSetSort(nodes);
2518 return(xmlXPathNodeTrailingSorted(nodes, node));
2519}
2520
2521/**
2522 * xmlXPathTrailingSorted:
2523 * @nodes1: a node-set, sorted by document order
2524 * @nodes2: a node-set, sorted by document order
2525 *
2526 * Implements the EXSLT - Sets trailing() function:
2527 * node-set set:trailing (node-set, node-set)
2528 *
2529 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2530 * in document order, @nodes1 if @nodes2 is NULL or empty or
2531 * an empty node-set if @nodes1 doesn't contain @nodes2
2532 */
2533xmlNodeSetPtr
2534xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2535 if (xmlXPathNodeSetIsEmpty(nodes2))
2536 return(nodes1);
2537 return(xmlXPathNodeTrailingSorted(nodes1,
2538 xmlXPathNodeSetItem(nodes2, 0)));
2539}
2540
2541/**
2542 * xmlXPathTrailing:
2543 * @nodes1: a node-set
2544 * @nodes2: a node-set
2545 *
2546 * Implements the EXSLT - Sets trailing() function:
2547 * node-set set:trailing (node-set, node-set)
2548 * @nodes1 and @nodes2 are sorted by document order, then
2549 * #xmlXPathTrailingSorted is called.
2550 *
2551 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2552 * in document order, @nodes1 if @nodes2 is NULL or empty or
2553 * an empty node-set if @nodes1 doesn't contain @nodes2
2554 */
2555xmlNodeSetPtr
2556xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2557 if (xmlXPathNodeSetIsEmpty(nodes2))
2558 return(nodes1);
2559 if (xmlXPathNodeSetIsEmpty(nodes1))
2560 return(xmlXPathNodeSetCreate(NULL));
2561 xmlXPathNodeSetSort(nodes1);
2562 xmlXPathNodeSetSort(nodes2);
2563 return(xmlXPathNodeTrailingSorted(nodes1,
2564 xmlXPathNodeSetItem(nodes2, 0)));
2565}
2566
Owen Taylor3473f882001-02-23 17:55:21 +00002567/************************************************************************
2568 * *
2569 * Routines to handle extra functions *
2570 * *
2571 ************************************************************************/
2572
2573/**
2574 * xmlXPathRegisterFunc:
2575 * @ctxt: the XPath context
2576 * @name: the function name
2577 * @f: the function implementation or NULL
2578 *
2579 * Register a new function. If @f is NULL it unregisters the function
2580 *
2581 * Returns 0 in case of success, -1 in case of error
2582 */
2583int
2584xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2585 xmlXPathFunction f) {
2586 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2587}
2588
2589/**
2590 * xmlXPathRegisterFuncNS:
2591 * @ctxt: the XPath context
2592 * @name: the function name
2593 * @ns_uri: the function namespace URI
2594 * @f: the function implementation or NULL
2595 *
2596 * Register a new function. If @f is NULL it unregisters the function
2597 *
2598 * Returns 0 in case of success, -1 in case of error
2599 */
2600int
2601xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2602 const xmlChar *ns_uri, xmlXPathFunction f) {
2603 if (ctxt == NULL)
2604 return(-1);
2605 if (name == NULL)
2606 return(-1);
2607
2608 if (ctxt->funcHash == NULL)
2609 ctxt->funcHash = xmlHashCreate(0);
2610 if (ctxt->funcHash == NULL)
2611 return(-1);
2612 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2613}
2614
2615/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002616 * xmlXPathRegisterFuncLookup:
2617 * @ctxt: the XPath context
2618 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002619 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00002620 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002621 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00002622 */
2623void
2624xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2625 xmlXPathFuncLookupFunc f,
2626 void *funcCtxt) {
2627 if (ctxt == NULL)
2628 return;
2629 ctxt->funcLookupFunc = (void *) f;
2630 ctxt->funcLookupData = funcCtxt;
2631}
2632
2633/**
Owen Taylor3473f882001-02-23 17:55:21 +00002634 * xmlXPathFunctionLookup:
2635 * @ctxt: the XPath context
2636 * @name: the function name
2637 *
2638 * Search in the Function array of the context for the given
2639 * function.
2640 *
2641 * Returns the xmlXPathFunction or NULL if not found
2642 */
2643xmlXPathFunction
2644xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002645 if (ctxt == NULL)
2646 return (NULL);
2647
2648 if (ctxt->funcLookupFunc != NULL) {
2649 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002650 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002651
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002652 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002653 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002654 if (ret != NULL)
2655 return(ret);
2656 }
Owen Taylor3473f882001-02-23 17:55:21 +00002657 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2658}
2659
2660/**
2661 * xmlXPathFunctionLookupNS:
2662 * @ctxt: the XPath context
2663 * @name: the function name
2664 * @ns_uri: the function namespace URI
2665 *
2666 * Search in the Function array of the context for the given
2667 * function.
2668 *
2669 * Returns the xmlXPathFunction or NULL if not found
2670 */
2671xmlXPathFunction
2672xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2673 const xmlChar *ns_uri) {
2674 if (ctxt == NULL)
2675 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002676 if (name == NULL)
2677 return(NULL);
2678
Thomas Broyerba4ad322001-07-26 16:55:21 +00002679 if (ctxt->funcLookupFunc != NULL) {
2680 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002681 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002682
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002683 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002684 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002685 if (ret != NULL)
2686 return(ret);
2687 }
2688
2689 if (ctxt->funcHash == NULL)
2690 return(NULL);
2691
Owen Taylor3473f882001-02-23 17:55:21 +00002692 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2693}
2694
2695/**
2696 * xmlXPathRegisteredFuncsCleanup:
2697 * @ctxt: the XPath context
2698 *
2699 * Cleanup the XPath context data associated to registered functions
2700 */
2701void
2702xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2703 if (ctxt == NULL)
2704 return;
2705
2706 xmlHashFree(ctxt->funcHash, NULL);
2707 ctxt->funcHash = NULL;
2708}
2709
2710/************************************************************************
2711 * *
2712 * Routines to handle Variable *
2713 * *
2714 ************************************************************************/
2715
2716/**
2717 * xmlXPathRegisterVariable:
2718 * @ctxt: the XPath context
2719 * @name: the variable name
2720 * @value: the variable value or NULL
2721 *
2722 * Register a new variable value. If @value is NULL it unregisters
2723 * the variable
2724 *
2725 * Returns 0 in case of success, -1 in case of error
2726 */
2727int
2728xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2729 xmlXPathObjectPtr value) {
2730 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2731}
2732
2733/**
2734 * xmlXPathRegisterVariableNS:
2735 * @ctxt: the XPath context
2736 * @name: the variable name
2737 * @ns_uri: the variable namespace URI
2738 * @value: the variable value or NULL
2739 *
2740 * Register a new variable value. If @value is NULL it unregisters
2741 * the variable
2742 *
2743 * Returns 0 in case of success, -1 in case of error
2744 */
2745int
2746xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2747 const xmlChar *ns_uri,
2748 xmlXPathObjectPtr value) {
2749 if (ctxt == NULL)
2750 return(-1);
2751 if (name == NULL)
2752 return(-1);
2753
2754 if (ctxt->varHash == NULL)
2755 ctxt->varHash = xmlHashCreate(0);
2756 if (ctxt->varHash == NULL)
2757 return(-1);
2758 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2759 (void *) value,
2760 (xmlHashDeallocator)xmlXPathFreeObject));
2761}
2762
2763/**
2764 * xmlXPathRegisterVariableLookup:
2765 * @ctxt: the XPath context
2766 * @f: the lookup function
2767 * @data: the lookup data
2768 *
2769 * register an external mechanism to do variable lookup
2770 */
2771void
2772xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2773 xmlXPathVariableLookupFunc f, void *data) {
2774 if (ctxt == NULL)
2775 return;
2776 ctxt->varLookupFunc = (void *) f;
2777 ctxt->varLookupData = data;
2778}
2779
2780/**
2781 * xmlXPathVariableLookup:
2782 * @ctxt: the XPath context
2783 * @name: the variable name
2784 *
2785 * Search in the Variable array of the context for the given
2786 * variable value.
2787 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002788 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002789 */
2790xmlXPathObjectPtr
2791xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2792 if (ctxt == NULL)
2793 return(NULL);
2794
2795 if (ctxt->varLookupFunc != NULL) {
2796 xmlXPathObjectPtr ret;
2797
2798 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2799 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00002800 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002801 }
2802 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
2803}
2804
2805/**
2806 * xmlXPathVariableLookupNS:
2807 * @ctxt: the XPath context
2808 * @name: the variable name
2809 * @ns_uri: the variable namespace URI
2810 *
2811 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00002812 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00002813 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002814 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002815 */
2816xmlXPathObjectPtr
2817xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2818 const xmlChar *ns_uri) {
2819 if (ctxt == NULL)
2820 return(NULL);
2821
2822 if (ctxt->varLookupFunc != NULL) {
2823 xmlXPathObjectPtr ret;
2824
2825 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2826 (ctxt->varLookupData, name, ns_uri);
2827 if (ret != NULL) return(ret);
2828 }
2829
2830 if (ctxt->varHash == NULL)
2831 return(NULL);
2832 if (name == NULL)
2833 return(NULL);
2834
Daniel Veillard8c357d52001-07-03 23:43:33 +00002835 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
2836 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00002837}
2838
2839/**
2840 * xmlXPathRegisteredVariablesCleanup:
2841 * @ctxt: the XPath context
2842 *
2843 * Cleanup the XPath context data associated to registered variables
2844 */
2845void
2846xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
2847 if (ctxt == NULL)
2848 return;
2849
Daniel Veillard76d66f42001-05-16 21:05:17 +00002850 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00002851 ctxt->varHash = NULL;
2852}
2853
2854/**
2855 * xmlXPathRegisterNs:
2856 * @ctxt: the XPath context
2857 * @prefix: the namespace prefix
2858 * @ns_uri: the namespace name
2859 *
2860 * Register a new namespace. If @ns_uri is NULL it unregisters
2861 * the namespace
2862 *
2863 * Returns 0 in case of success, -1 in case of error
2864 */
2865int
2866xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
2867 const xmlChar *ns_uri) {
2868 if (ctxt == NULL)
2869 return(-1);
2870 if (prefix == NULL)
2871 return(-1);
2872
2873 if (ctxt->nsHash == NULL)
2874 ctxt->nsHash = xmlHashCreate(10);
2875 if (ctxt->nsHash == NULL)
2876 return(-1);
Daniel Veillard42766c02002-08-22 20:52:17 +00002877 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00002878 (xmlHashDeallocator)xmlFree));
2879}
2880
2881/**
2882 * xmlXPathNsLookup:
2883 * @ctxt: the XPath context
2884 * @prefix: the namespace prefix value
2885 *
2886 * Search in the namespace declaration array of the context for the given
2887 * namespace name associated to the given prefix
2888 *
2889 * Returns the value or NULL if not found
2890 */
2891const xmlChar *
2892xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
2893 if (ctxt == NULL)
2894 return(NULL);
2895 if (prefix == NULL)
2896 return(NULL);
2897
2898#ifdef XML_XML_NAMESPACE
2899 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
2900 return(XML_XML_NAMESPACE);
2901#endif
2902
Daniel Veillardc8f620b2001-04-30 20:31:33 +00002903 if (ctxt->namespaces != NULL) {
2904 int i;
2905
2906 for (i = 0;i < ctxt->nsNr;i++) {
2907 if ((ctxt->namespaces[i] != NULL) &&
2908 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
2909 return(ctxt->namespaces[i]->href);
2910 }
2911 }
Owen Taylor3473f882001-02-23 17:55:21 +00002912
2913 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
2914}
2915
2916/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002917 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00002918 * @ctxt: the XPath context
2919 *
2920 * Cleanup the XPath context data associated to registered variables
2921 */
2922void
2923xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
2924 if (ctxt == NULL)
2925 return;
2926
Daniel Veillard42766c02002-08-22 20:52:17 +00002927 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00002928 ctxt->nsHash = NULL;
2929}
2930
2931/************************************************************************
2932 * *
2933 * Routines to handle Values *
2934 * *
2935 ************************************************************************/
2936
2937/* Allocations are terrible, one need to optimize all this !!! */
2938
2939/**
2940 * xmlXPathNewFloat:
2941 * @val: the double value
2942 *
2943 * Create a new xmlXPathObjectPtr of type double and of value @val
2944 *
2945 * Returns the newly created object.
2946 */
2947xmlXPathObjectPtr
2948xmlXPathNewFloat(double val) {
2949 xmlXPathObjectPtr ret;
2950
2951 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2952 if (ret == NULL) {
2953 xmlGenericError(xmlGenericErrorContext,
2954 "xmlXPathNewFloat: out of memory\n");
2955 return(NULL);
2956 }
2957 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2958 ret->type = XPATH_NUMBER;
2959 ret->floatval = val;
2960 return(ret);
2961}
2962
2963/**
2964 * xmlXPathNewBoolean:
2965 * @val: the boolean value
2966 *
2967 * Create a new xmlXPathObjectPtr of type boolean and of value @val
2968 *
2969 * Returns the newly created object.
2970 */
2971xmlXPathObjectPtr
2972xmlXPathNewBoolean(int val) {
2973 xmlXPathObjectPtr ret;
2974
2975 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2976 if (ret == NULL) {
2977 xmlGenericError(xmlGenericErrorContext,
2978 "xmlXPathNewBoolean: out of memory\n");
2979 return(NULL);
2980 }
2981 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2982 ret->type = XPATH_BOOLEAN;
2983 ret->boolval = (val != 0);
2984 return(ret);
2985}
2986
2987/**
2988 * xmlXPathNewString:
2989 * @val: the xmlChar * value
2990 *
2991 * Create a new xmlXPathObjectPtr of type string and of value @val
2992 *
2993 * Returns the newly created object.
2994 */
2995xmlXPathObjectPtr
2996xmlXPathNewString(const xmlChar *val) {
2997 xmlXPathObjectPtr ret;
2998
2999 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3000 if (ret == NULL) {
3001 xmlGenericError(xmlGenericErrorContext,
3002 "xmlXPathNewString: out of memory\n");
3003 return(NULL);
3004 }
3005 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3006 ret->type = XPATH_STRING;
3007 if (val != NULL)
3008 ret->stringval = xmlStrdup(val);
3009 else
3010 ret->stringval = xmlStrdup((const xmlChar *)"");
3011 return(ret);
3012}
3013
3014/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003015 * xmlXPathWrapString:
3016 * @val: the xmlChar * value
3017 *
3018 * Wraps the @val string into an XPath object.
3019 *
3020 * Returns the newly created object.
3021 */
3022xmlXPathObjectPtr
3023xmlXPathWrapString (xmlChar *val) {
3024 xmlXPathObjectPtr ret;
3025
3026 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3027 if (ret == NULL) {
3028 xmlGenericError(xmlGenericErrorContext,
3029 "xmlXPathWrapString: out of memory\n");
3030 return(NULL);
3031 }
3032 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3033 ret->type = XPATH_STRING;
3034 ret->stringval = val;
3035 return(ret);
3036}
3037
3038/**
Owen Taylor3473f882001-02-23 17:55:21 +00003039 * xmlXPathNewCString:
3040 * @val: the char * value
3041 *
3042 * Create a new xmlXPathObjectPtr of type string and of value @val
3043 *
3044 * Returns the newly created object.
3045 */
3046xmlXPathObjectPtr
3047xmlXPathNewCString(const char *val) {
3048 xmlXPathObjectPtr ret;
3049
3050 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3051 if (ret == NULL) {
3052 xmlGenericError(xmlGenericErrorContext,
3053 "xmlXPathNewCString: out of memory\n");
3054 return(NULL);
3055 }
3056 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3057 ret->type = XPATH_STRING;
3058 ret->stringval = xmlStrdup(BAD_CAST val);
3059 return(ret);
3060}
3061
3062/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003063 * xmlXPathWrapCString:
3064 * @val: the char * value
3065 *
3066 * Wraps a string into an XPath object.
3067 *
3068 * Returns the newly created object.
3069 */
3070xmlXPathObjectPtr
3071xmlXPathWrapCString (char * val) {
3072 return(xmlXPathWrapString((xmlChar *)(val)));
3073}
3074
3075/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003076 * xmlXPathWrapExternal:
3077 * @val: the user data
3078 *
3079 * Wraps the @val data into an XPath object.
3080 *
3081 * Returns the newly created object.
3082 */
3083xmlXPathObjectPtr
3084xmlXPathWrapExternal (void *val) {
3085 xmlXPathObjectPtr ret;
3086
3087 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3088 if (ret == NULL) {
3089 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003090 "xmlXPathWrapExternal: out of memory\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003091 return(NULL);
3092 }
3093 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3094 ret->type = XPATH_USERS;
3095 ret->user = val;
3096 return(ret);
3097}
3098
3099/**
Owen Taylor3473f882001-02-23 17:55:21 +00003100 * xmlXPathObjectCopy:
3101 * @val: the original object
3102 *
3103 * allocate a new copy of a given object
3104 *
3105 * Returns the newly created object.
3106 */
3107xmlXPathObjectPtr
3108xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3109 xmlXPathObjectPtr ret;
3110
3111 if (val == NULL)
3112 return(NULL);
3113
3114 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3115 if (ret == NULL) {
3116 xmlGenericError(xmlGenericErrorContext,
3117 "xmlXPathObjectCopy: out of memory\n");
3118 return(NULL);
3119 }
3120 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3121 switch (val->type) {
3122 case XPATH_BOOLEAN:
3123 case XPATH_NUMBER:
3124 case XPATH_POINT:
3125 case XPATH_RANGE:
3126 break;
3127 case XPATH_STRING:
3128 ret->stringval = xmlStrdup(val->stringval);
3129 break;
3130 case XPATH_XSLT_TREE:
3131 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003132 (val->nodesetval->nodeTab != NULL)) {
3133 ret->boolval = 1;
Daniel Veillard6ab38382001-10-06 13:08:27 +00003134 ret->user = xmlDocCopyNode(val->nodesetval->nodeTab[0],
3135 val->nodesetval->nodeTab[0]->doc, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003136 ret->nodesetval = xmlXPathNodeSetCreate(
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003137 (xmlNodePtr) ret->user);
3138 } else
Owen Taylor3473f882001-02-23 17:55:21 +00003139 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003140 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00003141 break;
3142 case XPATH_NODESET:
3143 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003144 /* Do not deallocate the copied tree value */
3145 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003146 break;
3147 case XPATH_LOCATIONSET:
3148#ifdef LIBXML_XPTR_ENABLED
3149 {
3150 xmlLocationSetPtr loc = val->user;
3151 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3152 break;
3153 }
3154#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00003155 case XPATH_USERS:
3156 ret->user = val->user;
3157 break;
3158 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00003159 xmlGenericError(xmlGenericErrorContext,
3160 "xmlXPathObjectCopy: unsupported type %d\n",
3161 val->type);
3162 break;
3163 }
3164 return(ret);
3165}
3166
3167/**
3168 * xmlXPathFreeObject:
3169 * @obj: the object to free
3170 *
3171 * Free up an xmlXPathObjectPtr object.
3172 */
3173void
3174xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3175 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003176 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00003177 if (obj->boolval) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003178 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003179 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00003180 xmlFreeNodeList((xmlNodePtr) obj->user);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003181 } else if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00003182 xmlXPathFreeValueTree(obj->nodesetval);
3183 } else {
3184 if (obj->nodesetval != NULL)
3185 xmlXPathFreeNodeSet(obj->nodesetval);
3186 }
Owen Taylor3473f882001-02-23 17:55:21 +00003187#ifdef LIBXML_XPTR_ENABLED
3188 } else if (obj->type == XPATH_LOCATIONSET) {
3189 if (obj->user != NULL)
3190 xmlXPtrFreeLocationSet(obj->user);
3191#endif
3192 } else if (obj->type == XPATH_STRING) {
3193 if (obj->stringval != NULL)
3194 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00003195 }
3196
Owen Taylor3473f882001-02-23 17:55:21 +00003197 xmlFree(obj);
3198}
3199
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003200
3201/************************************************************************
3202 * *
3203 * Type Casting Routines *
3204 * *
3205 ************************************************************************/
3206
3207/**
3208 * xmlXPathCastBooleanToString:
3209 * @val: a boolean
3210 *
3211 * Converts a boolean to its string value.
3212 *
3213 * Returns a newly allocated string.
3214 */
3215xmlChar *
3216xmlXPathCastBooleanToString (int val) {
3217 xmlChar *ret;
3218 if (val)
3219 ret = xmlStrdup((const xmlChar *) "true");
3220 else
3221 ret = xmlStrdup((const xmlChar *) "false");
3222 return(ret);
3223}
3224
3225/**
3226 * xmlXPathCastNumberToString:
3227 * @val: a number
3228 *
3229 * Converts a number to its string value.
3230 *
3231 * Returns a newly allocated string.
3232 */
3233xmlChar *
3234xmlXPathCastNumberToString (double val) {
3235 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00003236 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003237 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003238 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003239 break;
3240 case -1:
3241 ret = xmlStrdup((const xmlChar *) "-Infinity");
3242 break;
3243 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003244 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003245 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00003246 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
3247 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003248 } else {
3249 /* could be improved */
3250 char buf[100];
3251 xmlXPathFormatNumber(val, buf, 100);
3252 ret = xmlStrdup((const xmlChar *) buf);
3253 }
3254 }
3255 return(ret);
3256}
3257
3258/**
3259 * xmlXPathCastNodeToString:
3260 * @node: a node
3261 *
3262 * Converts a node to its string value.
3263 *
3264 * Returns a newly allocated string.
3265 */
3266xmlChar *
3267xmlXPathCastNodeToString (xmlNodePtr node) {
Daniel Veillard23b1f372002-04-18 15:50:05 +00003268 if ((node != NULL) && (node->type == XML_DOCUMENT_NODE))
3269 node = xmlDocGetRootElement((xmlDocPtr) node);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003270 return(xmlNodeGetContent(node));
3271}
3272
3273/**
3274 * xmlXPathCastNodeSetToString:
3275 * @ns: a node-set
3276 *
3277 * Converts a node-set to its string value.
3278 *
3279 * Returns a newly allocated string.
3280 */
3281xmlChar *
3282xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3283 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3284 return(xmlStrdup((const xmlChar *) ""));
3285
3286 xmlXPathNodeSetSort(ns);
3287 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3288}
3289
3290/**
3291 * xmlXPathCastToString:
3292 * @val: an XPath object
3293 *
3294 * Converts an existing object to its string() equivalent
3295 *
3296 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003297 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003298 * string object).
3299 */
3300xmlChar *
3301xmlXPathCastToString(xmlXPathObjectPtr val) {
3302 xmlChar *ret = NULL;
3303
3304 if (val == NULL)
3305 return(xmlStrdup((const xmlChar *) ""));
3306 switch (val->type) {
3307 case XPATH_UNDEFINED:
3308#ifdef DEBUG_EXPR
3309 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3310#endif
3311 ret = xmlStrdup((const xmlChar *) "");
3312 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003313 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003314 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003315 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3316 break;
3317 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00003318 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003319 case XPATH_BOOLEAN:
3320 ret = xmlXPathCastBooleanToString(val->boolval);
3321 break;
3322 case XPATH_NUMBER: {
3323 ret = xmlXPathCastNumberToString(val->floatval);
3324 break;
3325 }
3326 case XPATH_USERS:
3327 case XPATH_POINT:
3328 case XPATH_RANGE:
3329 case XPATH_LOCATIONSET:
3330 TODO
3331 ret = xmlStrdup((const xmlChar *) "");
3332 break;
3333 }
3334 return(ret);
3335}
3336
3337/**
3338 * xmlXPathConvertString:
3339 * @val: an XPath object
3340 *
3341 * Converts an existing object to its string() equivalent
3342 *
3343 * Returns the new object, the old one is freed (or the operation
3344 * is done directly on @val)
3345 */
3346xmlXPathObjectPtr
3347xmlXPathConvertString(xmlXPathObjectPtr val) {
3348 xmlChar *res = NULL;
3349
3350 if (val == NULL)
3351 return(xmlXPathNewCString(""));
3352
3353 switch (val->type) {
3354 case XPATH_UNDEFINED:
3355#ifdef DEBUG_EXPR
3356 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3357#endif
3358 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003359 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003360 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003361 res = xmlXPathCastNodeSetToString(val->nodesetval);
3362 break;
3363 case XPATH_STRING:
3364 return(val);
3365 case XPATH_BOOLEAN:
3366 res = xmlXPathCastBooleanToString(val->boolval);
3367 break;
3368 case XPATH_NUMBER:
3369 res = xmlXPathCastNumberToString(val->floatval);
3370 break;
3371 case XPATH_USERS:
3372 case XPATH_POINT:
3373 case XPATH_RANGE:
3374 case XPATH_LOCATIONSET:
3375 TODO;
3376 break;
3377 }
3378 xmlXPathFreeObject(val);
3379 if (res == NULL)
3380 return(xmlXPathNewCString(""));
3381 return(xmlXPathWrapString(res));
3382}
3383
3384/**
3385 * xmlXPathCastBooleanToNumber:
3386 * @val: a boolean
3387 *
3388 * Converts a boolean to its number value
3389 *
3390 * Returns the number value
3391 */
3392double
3393xmlXPathCastBooleanToNumber(int val) {
3394 if (val)
3395 return(1.0);
3396 return(0.0);
3397}
3398
3399/**
3400 * xmlXPathCastStringToNumber:
3401 * @val: a string
3402 *
3403 * Converts a string to its number value
3404 *
3405 * Returns the number value
3406 */
3407double
3408xmlXPathCastStringToNumber(const xmlChar * val) {
3409 return(xmlXPathStringEvalNumber(val));
3410}
3411
3412/**
3413 * xmlXPathCastNodeToNumber:
3414 * @node: a node
3415 *
3416 * Converts a node to its number value
3417 *
3418 * Returns the number value
3419 */
3420double
3421xmlXPathCastNodeToNumber (xmlNodePtr node) {
3422 xmlChar *strval;
3423 double ret;
3424
3425 if (node == NULL)
3426 return(xmlXPathNAN);
3427 strval = xmlXPathCastNodeToString(node);
3428 if (strval == NULL)
3429 return(xmlXPathNAN);
3430 ret = xmlXPathCastStringToNumber(strval);
3431 xmlFree(strval);
3432
3433 return(ret);
3434}
3435
3436/**
3437 * xmlXPathCastNodeSetToNumber:
3438 * @ns: a node-set
3439 *
3440 * Converts a node-set to its number value
3441 *
3442 * Returns the number value
3443 */
3444double
3445xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3446 xmlChar *str;
3447 double ret;
3448
3449 if (ns == NULL)
3450 return(xmlXPathNAN);
3451 str = xmlXPathCastNodeSetToString(ns);
3452 ret = xmlXPathCastStringToNumber(str);
3453 xmlFree(str);
3454 return(ret);
3455}
3456
3457/**
3458 * xmlXPathCastToNumber:
3459 * @val: an XPath object
3460 *
3461 * Converts an XPath object to its number value
3462 *
3463 * Returns the number value
3464 */
3465double
3466xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3467 double ret = 0.0;
3468
3469 if (val == NULL)
3470 return(xmlXPathNAN);
3471 switch (val->type) {
3472 case XPATH_UNDEFINED:
3473#ifdef DEGUB_EXPR
3474 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3475#endif
3476 ret = xmlXPathNAN;
3477 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003478 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003479 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003480 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3481 break;
3482 case XPATH_STRING:
3483 ret = xmlXPathCastStringToNumber(val->stringval);
3484 break;
3485 case XPATH_NUMBER:
3486 ret = val->floatval;
3487 break;
3488 case XPATH_BOOLEAN:
3489 ret = xmlXPathCastBooleanToNumber(val->boolval);
3490 break;
3491 case XPATH_USERS:
3492 case XPATH_POINT:
3493 case XPATH_RANGE:
3494 case XPATH_LOCATIONSET:
3495 TODO;
3496 ret = xmlXPathNAN;
3497 break;
3498 }
3499 return(ret);
3500}
3501
3502/**
3503 * xmlXPathConvertNumber:
3504 * @val: an XPath object
3505 *
3506 * Converts an existing object to its number() equivalent
3507 *
3508 * Returns the new object, the old one is freed (or the operation
3509 * is done directly on @val)
3510 */
3511xmlXPathObjectPtr
3512xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3513 xmlXPathObjectPtr ret;
3514
3515 if (val == NULL)
3516 return(xmlXPathNewFloat(0.0));
3517 if (val->type == XPATH_NUMBER)
3518 return(val);
3519 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3520 xmlXPathFreeObject(val);
3521 return(ret);
3522}
3523
3524/**
3525 * xmlXPathCastNumberToBoolean:
3526 * @val: a number
3527 *
3528 * Converts a number to its boolean value
3529 *
3530 * Returns the boolean value
3531 */
3532int
3533xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003534 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003535 return(0);
3536 return(1);
3537}
3538
3539/**
3540 * xmlXPathCastStringToBoolean:
3541 * @val: a string
3542 *
3543 * Converts a string to its boolean value
3544 *
3545 * Returns the boolean value
3546 */
3547int
3548xmlXPathCastStringToBoolean (const xmlChar *val) {
3549 if ((val == NULL) || (xmlStrlen(val) == 0))
3550 return(0);
3551 return(1);
3552}
3553
3554/**
3555 * xmlXPathCastNodeSetToBoolean:
3556 * @ns: a node-set
3557 *
3558 * Converts a node-set to its boolean value
3559 *
3560 * Returns the boolean value
3561 */
3562int
3563xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3564 if ((ns == NULL) || (ns->nodeNr == 0))
3565 return(0);
3566 return(1);
3567}
3568
3569/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003570 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003571 * @val: an XPath object
3572 *
3573 * Converts an XPath object to its boolean value
3574 *
3575 * Returns the boolean value
3576 */
3577int
3578xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3579 int ret = 0;
3580
3581 if (val == NULL)
3582 return(0);
3583 switch (val->type) {
3584 case XPATH_UNDEFINED:
3585#ifdef DEBUG_EXPR
3586 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3587#endif
3588 ret = 0;
3589 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003590 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003591 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003592 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3593 break;
3594 case XPATH_STRING:
3595 ret = xmlXPathCastStringToBoolean(val->stringval);
3596 break;
3597 case XPATH_NUMBER:
3598 ret = xmlXPathCastNumberToBoolean(val->floatval);
3599 break;
3600 case XPATH_BOOLEAN:
3601 ret = val->boolval;
3602 break;
3603 case XPATH_USERS:
3604 case XPATH_POINT:
3605 case XPATH_RANGE:
3606 case XPATH_LOCATIONSET:
3607 TODO;
3608 ret = 0;
3609 break;
3610 }
3611 return(ret);
3612}
3613
3614
3615/**
3616 * xmlXPathConvertBoolean:
3617 * @val: an XPath object
3618 *
3619 * Converts an existing object to its boolean() equivalent
3620 *
3621 * Returns the new object, the old one is freed (or the operation
3622 * is done directly on @val)
3623 */
3624xmlXPathObjectPtr
3625xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3626 xmlXPathObjectPtr ret;
3627
3628 if (val == NULL)
3629 return(xmlXPathNewBoolean(0));
3630 if (val->type == XPATH_BOOLEAN)
3631 return(val);
3632 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3633 xmlXPathFreeObject(val);
3634 return(ret);
3635}
3636
Owen Taylor3473f882001-02-23 17:55:21 +00003637/************************************************************************
3638 * *
3639 * Routines to handle XPath contexts *
3640 * *
3641 ************************************************************************/
3642
3643/**
3644 * xmlXPathNewContext:
3645 * @doc: the XML document
3646 *
3647 * Create a new xmlXPathContext
3648 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00003649 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00003650 */
3651xmlXPathContextPtr
3652xmlXPathNewContext(xmlDocPtr doc) {
3653 xmlXPathContextPtr ret;
3654
3655 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3656 if (ret == NULL) {
3657 xmlGenericError(xmlGenericErrorContext,
3658 "xmlXPathNewContext: out of memory\n");
3659 return(NULL);
3660 }
3661 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3662 ret->doc = doc;
3663 ret->node = NULL;
3664
3665 ret->varHash = NULL;
3666
3667 ret->nb_types = 0;
3668 ret->max_types = 0;
3669 ret->types = NULL;
3670
3671 ret->funcHash = xmlHashCreate(0);
3672
3673 ret->nb_axis = 0;
3674 ret->max_axis = 0;
3675 ret->axis = NULL;
3676
3677 ret->nsHash = NULL;
3678 ret->user = NULL;
3679
3680 ret->contextSize = -1;
3681 ret->proximityPosition = -1;
3682
3683 xmlXPathRegisterAllFunctions(ret);
3684
3685 return(ret);
3686}
3687
3688/**
3689 * xmlXPathFreeContext:
3690 * @ctxt: the context to free
3691 *
3692 * Free up an xmlXPathContext
3693 */
3694void
3695xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3696 xmlXPathRegisteredNsCleanup(ctxt);
3697 xmlXPathRegisteredFuncsCleanup(ctxt);
3698 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003699 xmlFree(ctxt);
3700}
3701
3702/************************************************************************
3703 * *
3704 * Routines to handle XPath parser contexts *
3705 * *
3706 ************************************************************************/
3707
3708#define CHECK_CTXT(ctxt) \
3709 if (ctxt == NULL) { \
3710 xmlGenericError(xmlGenericErrorContext, \
3711 "%s:%d Internal error: ctxt == NULL\n", \
3712 __FILE__, __LINE__); \
3713 } \
3714
3715
3716#define CHECK_CONTEXT(ctxt) \
3717 if (ctxt == NULL) { \
3718 xmlGenericError(xmlGenericErrorContext, \
3719 "%s:%d Internal error: no context\n", \
3720 __FILE__, __LINE__); \
3721 } \
3722 else if (ctxt->doc == NULL) { \
3723 xmlGenericError(xmlGenericErrorContext, \
3724 "%s:%d Internal error: no document\n", \
3725 __FILE__, __LINE__); \
3726 } \
3727 else if (ctxt->doc->children == NULL) { \
3728 xmlGenericError(xmlGenericErrorContext, \
3729 "%s:%d Internal error: document without root\n", \
3730 __FILE__, __LINE__); \
3731 } \
3732
3733
3734/**
3735 * xmlXPathNewParserContext:
3736 * @str: the XPath expression
3737 * @ctxt: the XPath context
3738 *
3739 * Create a new xmlXPathParserContext
3740 *
3741 * Returns the xmlXPathParserContext just allocated.
3742 */
3743xmlXPathParserContextPtr
3744xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3745 xmlXPathParserContextPtr ret;
3746
3747 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3748 if (ret == NULL) {
3749 xmlGenericError(xmlGenericErrorContext,
3750 "xmlXPathNewParserContext: out of memory\n");
3751 return(NULL);
3752 }
3753 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3754 ret->cur = ret->base = str;
3755 ret->context = ctxt;
3756
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003757 ret->comp = xmlXPathNewCompExpr();
3758 if (ret->comp == NULL) {
3759 xmlFree(ret->valueTab);
3760 xmlFree(ret);
3761 return(NULL);
3762 }
3763
3764 return(ret);
3765}
3766
3767/**
3768 * xmlXPathCompParserContext:
3769 * @comp: the XPath compiled expression
3770 * @ctxt: the XPath context
3771 *
3772 * Create a new xmlXPathParserContext when processing a compiled expression
3773 *
3774 * Returns the xmlXPathParserContext just allocated.
3775 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003776static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003777xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3778 xmlXPathParserContextPtr ret;
3779
3780 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3781 if (ret == NULL) {
3782 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003783 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003784 return(NULL);
3785 }
3786 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3787
Owen Taylor3473f882001-02-23 17:55:21 +00003788 /* Allocate the value stack */
3789 ret->valueTab = (xmlXPathObjectPtr *)
3790 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003791 if (ret->valueTab == NULL) {
3792 xmlFree(ret);
3793 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003794 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003795 return(NULL);
3796 }
Owen Taylor3473f882001-02-23 17:55:21 +00003797 ret->valueNr = 0;
3798 ret->valueMax = 10;
3799 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003800
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00003801 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003802 ret->comp = comp;
3803
Owen Taylor3473f882001-02-23 17:55:21 +00003804 return(ret);
3805}
3806
3807/**
3808 * xmlXPathFreeParserContext:
3809 * @ctxt: the context to free
3810 *
3811 * Free up an xmlXPathParserContext
3812 */
3813void
3814xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
3815 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003816 xmlFree(ctxt->valueTab);
3817 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003818 if (ctxt->comp)
3819 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00003820 xmlFree(ctxt);
3821}
3822
3823/************************************************************************
3824 * *
3825 * The implicit core function library *
3826 * *
3827 ************************************************************************/
3828
Owen Taylor3473f882001-02-23 17:55:21 +00003829/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00003830 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00003831 * @node: a node pointer
3832 *
3833 * Function computing the beginning of the string value of the node,
3834 * used to speed up comparisons
3835 *
3836 * Returns an int usable as a hash
3837 */
3838static unsigned int
3839xmlXPathNodeValHash(xmlNodePtr node) {
3840 int len = 2;
3841 const xmlChar * string = NULL;
3842 xmlNodePtr tmp = NULL;
3843 unsigned int ret = 0;
3844
3845 if (node == NULL)
3846 return(0);
3847
3848
3849 switch (node->type) {
3850 case XML_COMMENT_NODE:
3851 case XML_PI_NODE:
3852 case XML_CDATA_SECTION_NODE:
3853 case XML_TEXT_NODE:
3854 string = node->content;
3855 if (string == NULL)
3856 return(0);
3857 if (string[0] == 0)
3858 return(0);
3859 return(((unsigned int) string[0]) +
3860 (((unsigned int) string[1]) << 8));
3861 case XML_NAMESPACE_DECL:
3862 string = ((xmlNsPtr)node)->href;
3863 if (string == NULL)
3864 return(0);
3865 if (string[0] == 0)
3866 return(0);
3867 return(((unsigned int) string[0]) +
3868 (((unsigned int) string[1]) << 8));
3869 case XML_ATTRIBUTE_NODE:
3870 tmp = ((xmlAttrPtr) node)->children;
3871 break;
3872 case XML_ELEMENT_NODE:
3873 tmp = node->children;
3874 break;
3875 default:
3876 return(0);
3877 }
3878 while (tmp != NULL) {
3879 switch (tmp->type) {
3880 case XML_COMMENT_NODE:
3881 case XML_PI_NODE:
3882 case XML_CDATA_SECTION_NODE:
3883 case XML_TEXT_NODE:
3884 string = tmp->content;
3885 break;
3886 case XML_NAMESPACE_DECL:
3887 string = ((xmlNsPtr)tmp)->href;
3888 break;
3889 default:
3890 break;
3891 }
3892 if ((string != NULL) && (string[0] != 0)) {
3893 if (string[0] == 0)
3894 return(0);
3895 if (len == 1) {
3896 return(ret + (((unsigned int) string[0]) << 8));
3897 }
3898 if (string[1] == 0) {
3899 len = 1;
3900 ret = (unsigned int) string[0];
3901 } else {
3902 return(((unsigned int) string[0]) +
3903 (((unsigned int) string[1]) << 8));
3904 }
3905 }
3906 /*
3907 * Skip to next node
3908 */
3909 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
3910 if (tmp->children->type != XML_ENTITY_DECL) {
3911 tmp = tmp->children;
3912 continue;
3913 }
3914 }
3915 if (tmp == node)
3916 break;
3917
3918 if (tmp->next != NULL) {
3919 tmp = tmp->next;
3920 continue;
3921 }
3922
3923 do {
3924 tmp = tmp->parent;
3925 if (tmp == NULL)
3926 break;
3927 if (tmp == node) {
3928 tmp = NULL;
3929 break;
3930 }
3931 if (tmp->next != NULL) {
3932 tmp = tmp->next;
3933 break;
3934 }
3935 } while (tmp != NULL);
3936 }
3937 return(ret);
3938}
3939
3940/**
3941 * xmlXPathStringHash:
3942 * @string: a string
3943 *
3944 * Function computing the beginning of the string value of the node,
3945 * used to speed up comparisons
3946 *
3947 * Returns an int usable as a hash
3948 */
3949static unsigned int
3950xmlXPathStringHash(const xmlChar * string) {
3951 if (string == NULL)
3952 return((unsigned int) 0);
3953 if (string[0] == 0)
3954 return(0);
3955 return(((unsigned int) string[0]) +
3956 (((unsigned int) string[1]) << 8));
3957}
3958
3959/**
Owen Taylor3473f882001-02-23 17:55:21 +00003960 * xmlXPathCompareNodeSetFloat:
3961 * @ctxt: the XPath Parser context
3962 * @inf: less than (1) or greater than (0)
3963 * @strict: is the comparison strict
3964 * @arg: the node set
3965 * @f: the value
3966 *
3967 * Implement the compare operation between a nodeset and a number
3968 * @ns < @val (1, 1, ...
3969 * @ns <= @val (1, 0, ...
3970 * @ns > @val (0, 1, ...
3971 * @ns >= @val (0, 0, ...
3972 *
3973 * If one object to be compared is a node-set and the other is a number,
3974 * then the comparison will be true if and only if there is a node in the
3975 * node-set such that the result of performing the comparison on the number
3976 * to be compared and on the result of converting the string-value of that
3977 * node to a number using the number function is true.
3978 *
3979 * Returns 0 or 1 depending on the results of the test.
3980 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003981static int
Owen Taylor3473f882001-02-23 17:55:21 +00003982xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
3983 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
3984 int i, ret = 0;
3985 xmlNodeSetPtr ns;
3986 xmlChar *str2;
3987
3988 if ((f == NULL) || (arg == NULL) ||
3989 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3990 xmlXPathFreeObject(arg);
3991 xmlXPathFreeObject(f);
3992 return(0);
3993 }
3994 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003995 if (ns != NULL) {
3996 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003997 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003998 if (str2 != NULL) {
3999 valuePush(ctxt,
4000 xmlXPathNewString(str2));
4001 xmlFree(str2);
4002 xmlXPathNumberFunction(ctxt, 1);
4003 valuePush(ctxt, xmlXPathObjectCopy(f));
4004 ret = xmlXPathCompareValues(ctxt, inf, strict);
4005 if (ret)
4006 break;
4007 }
4008 }
Owen Taylor3473f882001-02-23 17:55:21 +00004009 }
4010 xmlXPathFreeObject(arg);
4011 xmlXPathFreeObject(f);
4012 return(ret);
4013}
4014
4015/**
4016 * xmlXPathCompareNodeSetString:
4017 * @ctxt: the XPath Parser context
4018 * @inf: less than (1) or greater than (0)
4019 * @strict: is the comparison strict
4020 * @arg: the node set
4021 * @s: the value
4022 *
4023 * Implement the compare operation between a nodeset and a string
4024 * @ns < @val (1, 1, ...
4025 * @ns <= @val (1, 0, ...
4026 * @ns > @val (0, 1, ...
4027 * @ns >= @val (0, 0, ...
4028 *
4029 * If one object to be compared is a node-set and the other is a string,
4030 * then the comparison will be true if and only if there is a node in
4031 * the node-set such that the result of performing the comparison on the
4032 * string-value of the node and the other string is true.
4033 *
4034 * Returns 0 or 1 depending on the results of the test.
4035 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004036static int
Owen Taylor3473f882001-02-23 17:55:21 +00004037xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
4038 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
4039 int i, ret = 0;
4040 xmlNodeSetPtr ns;
4041 xmlChar *str2;
4042
4043 if ((s == NULL) || (arg == NULL) ||
4044 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4045 xmlXPathFreeObject(arg);
4046 xmlXPathFreeObject(s);
4047 return(0);
4048 }
4049 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004050 if (ns != NULL) {
4051 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004052 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004053 if (str2 != NULL) {
4054 valuePush(ctxt,
4055 xmlXPathNewString(str2));
4056 xmlFree(str2);
4057 valuePush(ctxt, xmlXPathObjectCopy(s));
4058 ret = xmlXPathCompareValues(ctxt, inf, strict);
4059 if (ret)
4060 break;
4061 }
4062 }
Owen Taylor3473f882001-02-23 17:55:21 +00004063 }
4064 xmlXPathFreeObject(arg);
4065 xmlXPathFreeObject(s);
4066 return(ret);
4067}
4068
4069/**
4070 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004071 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00004072 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004073 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00004074 * @arg2: the second node set object
4075 *
4076 * Implement the compare operation on nodesets:
4077 *
4078 * If both objects to be compared are node-sets, then the comparison
4079 * will be true if and only if there is a node in the first node-set
4080 * and a node in the second node-set such that the result of performing
4081 * the comparison on the string-values of the two nodes is true.
4082 * ....
4083 * When neither object to be compared is a node-set and the operator
4084 * is <=, <, >= or >, then the objects are compared by converting both
4085 * objects to numbers and comparing the numbers according to IEEE 754.
4086 * ....
4087 * The number function converts its argument to a number as follows:
4088 * - a string that consists of optional whitespace followed by an
4089 * optional minus sign followed by a Number followed by whitespace
4090 * is converted to the IEEE 754 number that is nearest (according
4091 * to the IEEE 754 round-to-nearest rule) to the mathematical value
4092 * represented by the string; any other string is converted to NaN
4093 *
4094 * Conclusion all nodes need to be converted first to their string value
4095 * and then the comparison must be done when possible
4096 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004097static int
4098xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00004099 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4100 int i, j, init = 0;
4101 double val1;
4102 double *values2;
4103 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004104 xmlNodeSetPtr ns1;
4105 xmlNodeSetPtr ns2;
4106
4107 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004108 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4109 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004110 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004111 }
Owen Taylor3473f882001-02-23 17:55:21 +00004112 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004113 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4114 xmlXPathFreeObject(arg1);
4115 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004116 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004117 }
Owen Taylor3473f882001-02-23 17:55:21 +00004118
4119 ns1 = arg1->nodesetval;
4120 ns2 = arg2->nodesetval;
4121
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004122 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004123 xmlXPathFreeObject(arg1);
4124 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004125 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004126 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004127 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004128 xmlXPathFreeObject(arg1);
4129 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004130 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004131 }
Owen Taylor3473f882001-02-23 17:55:21 +00004132
4133 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4134 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004135 xmlXPathFreeObject(arg1);
4136 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004137 return(0);
4138 }
4139 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004140 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004141 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004142 continue;
4143 for (j = 0;j < ns2->nodeNr;j++) {
4144 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004145 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004146 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004147 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004148 continue;
4149 if (inf && strict)
4150 ret = (val1 < values2[j]);
4151 else if (inf && !strict)
4152 ret = (val1 <= values2[j]);
4153 else if (!inf && strict)
4154 ret = (val1 > values2[j]);
4155 else if (!inf && !strict)
4156 ret = (val1 >= values2[j]);
4157 if (ret)
4158 break;
4159 }
4160 if (ret)
4161 break;
4162 init = 1;
4163 }
4164 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004165 xmlXPathFreeObject(arg1);
4166 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004167 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004168}
4169
4170/**
4171 * xmlXPathCompareNodeSetValue:
4172 * @ctxt: the XPath Parser context
4173 * @inf: less than (1) or greater than (0)
4174 * @strict: is the comparison strict
4175 * @arg: the node set
4176 * @val: the value
4177 *
4178 * Implement the compare operation between a nodeset and a value
4179 * @ns < @val (1, 1, ...
4180 * @ns <= @val (1, 0, ...
4181 * @ns > @val (0, 1, ...
4182 * @ns >= @val (0, 0, ...
4183 *
4184 * If one object to be compared is a node-set and the other is a boolean,
4185 * then the comparison will be true if and only if the result of performing
4186 * the comparison on the boolean and on the result of converting
4187 * the node-set to a boolean using the boolean function is true.
4188 *
4189 * Returns 0 or 1 depending on the results of the test.
4190 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004191static int
Owen Taylor3473f882001-02-23 17:55:21 +00004192xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4193 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4194 if ((val == NULL) || (arg == NULL) ||
4195 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4196 return(0);
4197
4198 switch(val->type) {
4199 case XPATH_NUMBER:
4200 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4201 case XPATH_NODESET:
4202 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004203 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004204 case XPATH_STRING:
4205 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4206 case XPATH_BOOLEAN:
4207 valuePush(ctxt, arg);
4208 xmlXPathBooleanFunction(ctxt, 1);
4209 valuePush(ctxt, val);
4210 return(xmlXPathCompareValues(ctxt, inf, strict));
4211 default:
4212 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004213 }
4214 return(0);
4215}
4216
4217/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004218 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00004219 * @arg: the nodeset object argument
4220 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00004221 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004222 *
4223 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4224 * If one object to be compared is a node-set and the other is a string,
4225 * then the comparison will be true if and only if there is a node in
4226 * the node-set such that the result of performing the comparison on the
4227 * string-value of the node and the other string is true.
4228 *
4229 * Returns 0 or 1 depending on the results of the test.
4230 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004231static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004232xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004233{
Owen Taylor3473f882001-02-23 17:55:21 +00004234 int i;
4235 xmlNodeSetPtr ns;
4236 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004237 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004238
4239 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004240 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4241 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004242 ns = arg->nodesetval;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004243 hash = xmlXPathStringHash(str);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004244 if (ns == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004245 return (0);
Daniel Veillard73c9c042001-07-05 20:02:54 +00004246 if (ns->nodeNr <= 0) {
4247 if (hash == 0)
William M. Brack0c022ad2002-07-12 00:56:01 +00004248 return(neq ^ 1);
4249 return(neq);
Daniel Veillard73c9c042001-07-05 20:02:54 +00004250 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004251 for (i = 0; i < ns->nodeNr; i++) {
4252 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4253 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4254 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4255 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004256 if (neq)
4257 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004258 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00004259 } else if (neq) {
4260 if (str2 != NULL)
4261 xmlFree(str2);
4262 return (1);
4263 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004264 if (str2 != NULL)
4265 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004266 } else if (neq)
4267 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00004268 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004269 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004270}
4271
4272/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004273 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00004274 * @arg: the nodeset object argument
4275 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00004276 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004277 *
4278 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4279 * If one object to be compared is a node-set and the other is a number,
4280 * then the comparison will be true if and only if there is a node in
4281 * the node-set such that the result of performing the comparison on the
4282 * number to be compared and on the result of converting the string-value
4283 * of that node to a number using the number function is true.
4284 *
4285 * Returns 0 or 1 depending on the results of the test.
4286 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004287static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004288xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
4289 xmlXPathObjectPtr arg, double f, int neq) {
4290 int i, ret=0;
4291 xmlNodeSetPtr ns;
4292 xmlChar *str2;
4293 xmlXPathObjectPtr val;
4294 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00004295
4296 if ((arg == NULL) ||
4297 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4298 return(0);
4299
William M. Brack0c022ad2002-07-12 00:56:01 +00004300 ns = arg->nodesetval;
4301 if (ns != NULL) {
4302 for (i=0;i<ns->nodeNr;i++) {
4303 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4304 if (str2 != NULL) {
4305 valuePush(ctxt, xmlXPathNewString(str2));
4306 xmlFree(str2);
4307 xmlXPathNumberFunction(ctxt, 1);
4308 val = valuePop(ctxt);
4309 v = val->floatval;
4310 xmlXPathFreeObject(val);
4311 if (!xmlXPathIsNaN(v)) {
4312 if ((!neq) && (v==f)) {
4313 ret = 1;
4314 break;
4315 } else if ((neq) && (v!=f)) {
4316 ret = 1;
4317 break;
4318 }
4319 }
4320 }
4321 }
4322 }
4323
4324 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004325}
4326
4327
4328/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004329 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00004330 * @arg1: first nodeset object argument
4331 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00004332 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004333 *
William M. Brack0c022ad2002-07-12 00:56:01 +00004334 * Implement the equal / not equal operation on XPath nodesets:
4335 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00004336 * If both objects to be compared are node-sets, then the comparison
4337 * will be true if and only if there is a node in the first node-set and
4338 * a node in the second node-set such that the result of performing the
4339 * comparison on the string-values of the two nodes is true.
4340 *
4341 * (needless to say, this is a costly operation)
4342 *
4343 * Returns 0 or 1 depending on the results of the test.
4344 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004345static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004346xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00004347 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004348 unsigned int *hashs1;
4349 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004350 xmlChar **values1;
4351 xmlChar **values2;
4352 int ret = 0;
4353 xmlNodeSetPtr ns1;
4354 xmlNodeSetPtr ns2;
4355
4356 if ((arg1 == NULL) ||
4357 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4358 return(0);
4359 if ((arg2 == NULL) ||
4360 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4361 return(0);
4362
4363 ns1 = arg1->nodesetval;
4364 ns2 = arg2->nodesetval;
4365
Daniel Veillard911f49a2001-04-07 15:39:35 +00004366 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004367 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004368 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004369 return(0);
4370
4371 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00004372 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00004373 */
William M. Brack0c022ad2002-07-12 00:56:01 +00004374 if (neq == 0)
4375 for (i = 0;i < ns1->nodeNr;i++)
4376 for (j = 0;j < ns2->nodeNr;j++)
4377 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4378 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00004379
4380 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
4381 if (values1 == NULL)
4382 return(0);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004383 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4384 if (hashs1 == NULL) {
4385 xmlFree(values1);
4386 return(0);
4387 }
Owen Taylor3473f882001-02-23 17:55:21 +00004388 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4389 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4390 if (values2 == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004391 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004392 xmlFree(values1);
4393 return(0);
4394 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004395 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4396 if (hashs2 == NULL) {
4397 xmlFree(hashs1);
4398 xmlFree(values1);
4399 xmlFree(values2);
4400 return(0);
4401 }
Owen Taylor3473f882001-02-23 17:55:21 +00004402 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4403 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004404 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004405 for (j = 0;j < ns2->nodeNr;j++) {
4406 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004407 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004408 if (hashs1[i] != hashs2[j]) {
4409 if (neq) {
4410 ret = 1;
4411 break;
4412 }
4413 }
4414 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004415 if (values1[i] == NULL)
4416 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4417 if (values2[j] == NULL)
4418 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004419 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004420 if (ret)
4421 break;
4422 }
Owen Taylor3473f882001-02-23 17:55:21 +00004423 }
4424 if (ret)
4425 break;
4426 }
4427 for (i = 0;i < ns1->nodeNr;i++)
4428 if (values1[i] != NULL)
4429 xmlFree(values1[i]);
4430 for (j = 0;j < ns2->nodeNr;j++)
4431 if (values2[j] != NULL)
4432 xmlFree(values2[j]);
4433 xmlFree(values1);
4434 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004435 xmlFree(hashs1);
4436 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004437 return(ret);
4438}
4439
William M. Brack0c022ad2002-07-12 00:56:01 +00004440static int
4441xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
4442 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00004443 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00004444 /*
4445 *At this point we are assured neither arg1 nor arg2
4446 *is a nodeset, so we can just pick the appropriate routine.
4447 */
Owen Taylor3473f882001-02-23 17:55:21 +00004448 switch (arg1->type) {
4449 case XPATH_UNDEFINED:
4450#ifdef DEBUG_EXPR
4451 xmlGenericError(xmlGenericErrorContext,
4452 "Equal: undefined\n");
4453#endif
4454 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004455 case XPATH_BOOLEAN:
4456 switch (arg2->type) {
4457 case XPATH_UNDEFINED:
4458#ifdef DEBUG_EXPR
4459 xmlGenericError(xmlGenericErrorContext,
4460 "Equal: undefined\n");
4461#endif
4462 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004463 case XPATH_BOOLEAN:
4464#ifdef DEBUG_EXPR
4465 xmlGenericError(xmlGenericErrorContext,
4466 "Equal: %d boolean %d \n",
4467 arg1->boolval, arg2->boolval);
4468#endif
4469 ret = (arg1->boolval == arg2->boolval);
4470 break;
4471 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00004472 ret = (arg1->boolval ==
4473 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004474 break;
4475 case XPATH_STRING:
4476 if ((arg2->stringval == NULL) ||
4477 (arg2->stringval[0] == 0)) ret = 0;
4478 else
4479 ret = 1;
4480 ret = (arg1->boolval == ret);
4481 break;
4482 case XPATH_USERS:
4483 case XPATH_POINT:
4484 case XPATH_RANGE:
4485 case XPATH_LOCATIONSET:
4486 TODO
4487 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004488 case XPATH_NODESET:
4489 case XPATH_XSLT_TREE:
4490 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004491 }
4492 break;
4493 case XPATH_NUMBER:
4494 switch (arg2->type) {
4495 case XPATH_UNDEFINED:
4496#ifdef DEBUG_EXPR
4497 xmlGenericError(xmlGenericErrorContext,
4498 "Equal: undefined\n");
4499#endif
4500 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004501 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00004502 ret = (arg2->boolval==
4503 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004504 break;
4505 case XPATH_STRING:
4506 valuePush(ctxt, arg2);
4507 xmlXPathNumberFunction(ctxt, 1);
4508 arg2 = valuePop(ctxt);
4509 /* no break on purpose */
4510 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004511 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004512 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4513 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004514 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4515 if (xmlXPathIsInf(arg2->floatval) == 1)
4516 ret = 1;
4517 else
4518 ret = 0;
4519 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4520 if (xmlXPathIsInf(arg2->floatval) == -1)
4521 ret = 1;
4522 else
4523 ret = 0;
4524 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4525 if (xmlXPathIsInf(arg1->floatval) == 1)
4526 ret = 1;
4527 else
4528 ret = 0;
4529 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4530 if (xmlXPathIsInf(arg1->floatval) == -1)
4531 ret = 1;
4532 else
4533 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004534 } else {
4535 ret = (arg1->floatval == arg2->floatval);
4536 }
Owen Taylor3473f882001-02-23 17:55:21 +00004537 break;
4538 case XPATH_USERS:
4539 case XPATH_POINT:
4540 case XPATH_RANGE:
4541 case XPATH_LOCATIONSET:
4542 TODO
4543 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004544 case XPATH_NODESET:
4545 case XPATH_XSLT_TREE:
4546 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004547 }
4548 break;
4549 case XPATH_STRING:
4550 switch (arg2->type) {
4551 case XPATH_UNDEFINED:
4552#ifdef DEBUG_EXPR
4553 xmlGenericError(xmlGenericErrorContext,
4554 "Equal: undefined\n");
4555#endif
4556 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004557 case XPATH_BOOLEAN:
4558 if ((arg1->stringval == NULL) ||
4559 (arg1->stringval[0] == 0)) ret = 0;
4560 else
4561 ret = 1;
4562 ret = (arg2->boolval == ret);
4563 break;
4564 case XPATH_STRING:
4565 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4566 break;
4567 case XPATH_NUMBER:
4568 valuePush(ctxt, arg1);
4569 xmlXPathNumberFunction(ctxt, 1);
4570 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004571 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004572 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4573 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004574 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4575 if (xmlXPathIsInf(arg2->floatval) == 1)
4576 ret = 1;
4577 else
4578 ret = 0;
4579 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4580 if (xmlXPathIsInf(arg2->floatval) == -1)
4581 ret = 1;
4582 else
4583 ret = 0;
4584 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4585 if (xmlXPathIsInf(arg1->floatval) == 1)
4586 ret = 1;
4587 else
4588 ret = 0;
4589 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4590 if (xmlXPathIsInf(arg1->floatval) == -1)
4591 ret = 1;
4592 else
4593 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004594 } else {
4595 ret = (arg1->floatval == arg2->floatval);
4596 }
Owen Taylor3473f882001-02-23 17:55:21 +00004597 break;
4598 case XPATH_USERS:
4599 case XPATH_POINT:
4600 case XPATH_RANGE:
4601 case XPATH_LOCATIONSET:
4602 TODO
4603 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004604 case XPATH_NODESET:
4605 case XPATH_XSLT_TREE:
4606 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004607 }
4608 break;
4609 case XPATH_USERS:
4610 case XPATH_POINT:
4611 case XPATH_RANGE:
4612 case XPATH_LOCATIONSET:
4613 TODO
4614 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004615 case XPATH_NODESET:
4616 case XPATH_XSLT_TREE:
4617 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004618 }
4619 xmlXPathFreeObject(arg1);
4620 xmlXPathFreeObject(arg2);
4621 return(ret);
4622}
4623
William M. Brack0c022ad2002-07-12 00:56:01 +00004624/**
4625 * xmlXPathEqualValues:
4626 * @ctxt: the XPath Parser context
4627 *
4628 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4629 *
4630 * Returns 0 or 1 depending on the results of the test.
4631 */
4632int
4633xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4634 xmlXPathObjectPtr arg1, arg2, argtmp;
4635 int ret = 0;
4636
4637 arg2 = valuePop(ctxt);
4638 arg1 = valuePop(ctxt);
4639 if ((arg1 == NULL) || (arg2 == NULL)) {
4640 if (arg1 != NULL)
4641 xmlXPathFreeObject(arg1);
4642 else
4643 xmlXPathFreeObject(arg2);
4644 XP_ERROR0(XPATH_INVALID_OPERAND);
4645 }
4646
4647 if (arg1 == arg2) {
4648#ifdef DEBUG_EXPR
4649 xmlGenericError(xmlGenericErrorContext,
4650 "Equal: by pointer\n");
4651#endif
4652 return(1);
4653 }
4654
4655 /*
4656 *If either argument is a nodeset, it's a 'special case'
4657 */
4658 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4659 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4660 /*
4661 *Hack it to assure arg1 is the nodeset
4662 */
4663 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4664 argtmp = arg2;
4665 arg2 = arg1;
4666 arg1 = argtmp;
4667 }
4668 switch (arg2->type) {
4669 case XPATH_UNDEFINED:
4670#ifdef DEBUG_EXPR
4671 xmlGenericError(xmlGenericErrorContext,
4672 "Equal: undefined\n");
4673#endif
4674 break;
4675 case XPATH_NODESET:
4676 case XPATH_XSLT_TREE:
4677 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
4678 break;
4679 case XPATH_BOOLEAN:
4680 if ((arg1->nodesetval == NULL) ||
4681 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4682 else
4683 ret = 1;
4684 ret = (ret == arg2->boolval);
4685 break;
4686 case XPATH_NUMBER:
4687 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
4688 break;
4689 case XPATH_STRING:
4690 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
4691 break;
4692 case XPATH_USERS:
4693 case XPATH_POINT:
4694 case XPATH_RANGE:
4695 case XPATH_LOCATIONSET:
4696 TODO
4697 break;
4698 }
4699 xmlXPathFreeObject(arg1);
4700 xmlXPathFreeObject(arg2);
4701 return(ret);
4702 }
4703
4704 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4705}
4706
4707/**
4708 * xmlXPathNotEqualValues:
4709 * @ctxt: the XPath Parser context
4710 *
4711 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4712 *
4713 * Returns 0 or 1 depending on the results of the test.
4714 */
4715int
4716xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
4717 xmlXPathObjectPtr arg1, arg2, argtmp;
4718 int ret = 0;
4719
4720 arg2 = valuePop(ctxt);
4721 arg1 = valuePop(ctxt);
4722 if ((arg1 == NULL) || (arg2 == NULL)) {
4723 if (arg1 != NULL)
4724 xmlXPathFreeObject(arg1);
4725 else
4726 xmlXPathFreeObject(arg2);
4727 XP_ERROR0(XPATH_INVALID_OPERAND);
4728 }
4729
4730 if (arg1 == arg2) {
4731#ifdef DEBUG_EXPR
4732 xmlGenericError(xmlGenericErrorContext,
4733 "NotEqual: by pointer\n");
4734#endif
4735 return(0);
4736 }
4737
4738 /*
4739 *If either argument is a nodeset, it's a 'special case'
4740 */
4741 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4742 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4743 /*
4744 *Hack it to assure arg1 is the nodeset
4745 */
4746 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4747 argtmp = arg2;
4748 arg2 = arg1;
4749 arg1 = argtmp;
4750 }
4751 switch (arg2->type) {
4752 case XPATH_UNDEFINED:
4753#ifdef DEBUG_EXPR
4754 xmlGenericError(xmlGenericErrorContext,
4755 "NotEqual: undefined\n");
4756#endif
4757 break;
4758 case XPATH_NODESET:
4759 case XPATH_XSLT_TREE:
4760 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
4761 break;
4762 case XPATH_BOOLEAN:
4763 if ((arg1->nodesetval == NULL) ||
4764 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4765 else
4766 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00004767 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00004768 break;
4769 case XPATH_NUMBER:
4770 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
4771 break;
4772 case XPATH_STRING:
4773 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
4774 break;
4775 case XPATH_USERS:
4776 case XPATH_POINT:
4777 case XPATH_RANGE:
4778 case XPATH_LOCATIONSET:
4779 TODO
4780 break;
4781 }
4782 xmlXPathFreeObject(arg1);
4783 xmlXPathFreeObject(arg2);
4784 return(ret);
4785 }
4786
4787 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4788}
Owen Taylor3473f882001-02-23 17:55:21 +00004789
4790/**
4791 * xmlXPathCompareValues:
4792 * @ctxt: the XPath Parser context
4793 * @inf: less than (1) or greater than (0)
4794 * @strict: is the comparison strict
4795 *
4796 * Implement the compare operation on XPath objects:
4797 * @arg1 < @arg2 (1, 1, ...
4798 * @arg1 <= @arg2 (1, 0, ...
4799 * @arg1 > @arg2 (0, 1, ...
4800 * @arg1 >= @arg2 (0, 0, ...
4801 *
4802 * When neither object to be compared is a node-set and the operator is
4803 * <=, <, >=, >, then the objects are compared by converted both objects
4804 * to numbers and comparing the numbers according to IEEE 754. The <
4805 * comparison will be true if and only if the first number is less than the
4806 * second number. The <= comparison will be true if and only if the first
4807 * number is less than or equal to the second number. The > comparison
4808 * will be true if and only if the first number is greater than the second
4809 * number. The >= comparison will be true if and only if the first number
4810 * is greater than or equal to the second number.
4811 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004812 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00004813 */
4814int
4815xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004816 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004817 xmlXPathObjectPtr arg1, arg2;
4818
William M. Brack0c022ad2002-07-12 00:56:01 +00004819 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00004820 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00004821 if ((arg1 == NULL) || (arg2 == NULL)) {
4822 if (arg1 != NULL)
4823 xmlXPathFreeObject(arg1);
4824 else
4825 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004826 XP_ERROR0(XPATH_INVALID_OPERAND);
4827 }
4828
William M. Brack0c022ad2002-07-12 00:56:01 +00004829 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4830 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4831 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
4832 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004833 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004834 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00004835 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004836 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
4837 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004838 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004839 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
4840 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00004841 }
4842 }
4843 return(ret);
4844 }
4845
4846 if (arg1->type != XPATH_NUMBER) {
4847 valuePush(ctxt, arg1);
4848 xmlXPathNumberFunction(ctxt, 1);
4849 arg1 = valuePop(ctxt);
4850 }
4851 if (arg1->type != XPATH_NUMBER) {
4852 xmlXPathFreeObject(arg1);
4853 xmlXPathFreeObject(arg2);
4854 XP_ERROR0(XPATH_INVALID_OPERAND);
4855 }
4856 if (arg2->type != XPATH_NUMBER) {
4857 valuePush(ctxt, arg2);
4858 xmlXPathNumberFunction(ctxt, 1);
4859 arg2 = valuePop(ctxt);
4860 }
4861 if (arg2->type != XPATH_NUMBER) {
4862 xmlXPathFreeObject(arg1);
4863 xmlXPathFreeObject(arg2);
4864 XP_ERROR0(XPATH_INVALID_OPERAND);
4865 }
4866 /*
4867 * Add tests for infinity and nan
4868 * => feedback on 3.4 for Inf and NaN
4869 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004870 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00004871 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004872 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004873 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004874 arg1i=xmlXPathIsInf(arg1->floatval);
4875 arg2i=xmlXPathIsInf(arg2->floatval);
4876 if (inf && strict) {
4877 if ((arg1i == -1 && arg2i != -1) ||
4878 (arg2i == 1 && arg1i != 1)) {
4879 ret = 1;
4880 } else if (arg1i == 0 && arg2i == 0) {
4881 ret = (arg1->floatval < arg2->floatval);
4882 } else {
4883 ret = 0;
4884 }
4885 }
4886 else if (inf && !strict) {
4887 if (arg1i == -1 || arg2i == 1) {
4888 ret = 1;
4889 } else if (arg1i == 0 && arg2i == 0) {
4890 ret = (arg1->floatval <= arg2->floatval);
4891 } else {
4892 ret = 0;
4893 }
4894 }
4895 else if (!inf && strict) {
4896 if ((arg1i == 1 && arg2i != 1) ||
4897 (arg2i == -1 && arg1i != -1)) {
4898 ret = 1;
4899 } else if (arg1i == 0 && arg2i == 0) {
4900 ret = (arg1->floatval > arg2->floatval);
4901 } else {
4902 ret = 0;
4903 }
4904 }
4905 else if (!inf && !strict) {
4906 if (arg1i == 1 || arg2i == -1) {
4907 ret = 1;
4908 } else if (arg1i == 0 && arg2i == 0) {
4909 ret = (arg1->floatval >= arg2->floatval);
4910 } else {
4911 ret = 0;
4912 }
4913 }
Daniel Veillard21458c82002-03-27 16:12:22 +00004914 }
Owen Taylor3473f882001-02-23 17:55:21 +00004915 xmlXPathFreeObject(arg1);
4916 xmlXPathFreeObject(arg2);
4917 return(ret);
4918}
4919
4920/**
4921 * xmlXPathValueFlipSign:
4922 * @ctxt: the XPath Parser context
4923 *
4924 * Implement the unary - operation on an XPath object
4925 * The numeric operators convert their operands to numbers as if
4926 * by calling the number function.
4927 */
4928void
4929xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004930 CAST_TO_NUMBER;
4931 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00004932 if (xmlXPathIsNaN(ctxt->value->floatval))
4933 ctxt->value->floatval=xmlXPathNAN;
4934 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
4935 ctxt->value->floatval=xmlXPathNINF;
4936 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
4937 ctxt->value->floatval=xmlXPathPINF;
4938 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00004939 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
4940 ctxt->value->floatval = xmlXPathNZERO;
4941 else
4942 ctxt->value->floatval = 0;
4943 }
4944 else
4945 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00004946}
4947
4948/**
4949 * xmlXPathAddValues:
4950 * @ctxt: the XPath Parser context
4951 *
4952 * Implement the add operation on XPath objects:
4953 * The numeric operators convert their operands to numbers as if
4954 * by calling the number function.
4955 */
4956void
4957xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
4958 xmlXPathObjectPtr arg;
4959 double val;
4960
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004961 arg = valuePop(ctxt);
4962 if (arg == NULL)
4963 XP_ERROR(XPATH_INVALID_OPERAND);
4964 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004965 xmlXPathFreeObject(arg);
4966
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004967 CAST_TO_NUMBER;
4968 CHECK_TYPE(XPATH_NUMBER);
4969 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00004970}
4971
4972/**
4973 * xmlXPathSubValues:
4974 * @ctxt: the XPath Parser context
4975 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004976 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00004977 * The numeric operators convert their operands to numbers as if
4978 * by calling the number function.
4979 */
4980void
4981xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
4982 xmlXPathObjectPtr arg;
4983 double val;
4984
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004985 arg = valuePop(ctxt);
4986 if (arg == NULL)
4987 XP_ERROR(XPATH_INVALID_OPERAND);
4988 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004989 xmlXPathFreeObject(arg);
4990
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004991 CAST_TO_NUMBER;
4992 CHECK_TYPE(XPATH_NUMBER);
4993 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004994}
4995
4996/**
4997 * xmlXPathMultValues:
4998 * @ctxt: the XPath Parser context
4999 *
5000 * Implement the multiply operation on XPath objects:
5001 * The numeric operators convert their operands to numbers as if
5002 * by calling the number function.
5003 */
5004void
5005xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
5006 xmlXPathObjectPtr arg;
5007 double val;
5008
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005009 arg = valuePop(ctxt);
5010 if (arg == NULL)
5011 XP_ERROR(XPATH_INVALID_OPERAND);
5012 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005013 xmlXPathFreeObject(arg);
5014
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005015 CAST_TO_NUMBER;
5016 CHECK_TYPE(XPATH_NUMBER);
5017 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005018}
5019
5020/**
5021 * xmlXPathDivValues:
5022 * @ctxt: the XPath Parser context
5023 *
5024 * Implement the div operation on XPath objects @arg1 / @arg2:
5025 * The numeric operators convert their operands to numbers as if
5026 * by calling the number function.
5027 */
5028void
5029xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
5030 xmlXPathObjectPtr arg;
5031 double val;
5032
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005033 arg = valuePop(ctxt);
5034 if (arg == NULL)
5035 XP_ERROR(XPATH_INVALID_OPERAND);
5036 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005037 xmlXPathFreeObject(arg);
5038
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005039 CAST_TO_NUMBER;
5040 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005041 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
5042 ctxt->value->floatval = xmlXPathNAN;
5043 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005044 if (ctxt->value->floatval == 0)
5045 ctxt->value->floatval = xmlXPathNAN;
5046 else if (ctxt->value->floatval > 0)
5047 ctxt->value->floatval = xmlXPathNINF;
5048 else if (ctxt->value->floatval < 0)
5049 ctxt->value->floatval = xmlXPathPINF;
5050 }
5051 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00005052 if (ctxt->value->floatval == 0)
5053 ctxt->value->floatval = xmlXPathNAN;
5054 else if (ctxt->value->floatval > 0)
5055 ctxt->value->floatval = xmlXPathPINF;
5056 else if (ctxt->value->floatval < 0)
5057 ctxt->value->floatval = xmlXPathNINF;
5058 } else
5059 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005060}
5061
5062/**
5063 * xmlXPathModValues:
5064 * @ctxt: the XPath Parser context
5065 *
5066 * Implement the mod operation on XPath objects: @arg1 / @arg2
5067 * The numeric operators convert their operands to numbers as if
5068 * by calling the number function.
5069 */
5070void
5071xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
5072 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005073 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00005074
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005075 arg = valuePop(ctxt);
5076 if (arg == NULL)
5077 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005078 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005079 xmlXPathFreeObject(arg);
5080
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005081 CAST_TO_NUMBER;
5082 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005083 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00005084 if (arg2 == 0)
5085 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005086 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00005087 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005088 }
Owen Taylor3473f882001-02-23 17:55:21 +00005089}
5090
5091/************************************************************************
5092 * *
5093 * The traversal functions *
5094 * *
5095 ************************************************************************/
5096
Owen Taylor3473f882001-02-23 17:55:21 +00005097/*
5098 * A traversal function enumerates nodes along an axis.
5099 * Initially it must be called with NULL, and it indicates
5100 * termination on the axis by returning NULL.
5101 */
5102typedef xmlNodePtr (*xmlXPathTraversalFunction)
5103 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
5104
5105/**
5106 * xmlXPathNextSelf:
5107 * @ctxt: the XPath Parser context
5108 * @cur: the current node in the traversal
5109 *
5110 * Traversal function for the "self" direction
5111 * The self axis contains just the context node itself
5112 *
5113 * Returns the next element following that axis
5114 */
5115xmlNodePtr
5116xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5117 if (cur == NULL)
5118 return(ctxt->context->node);
5119 return(NULL);
5120}
5121
5122/**
5123 * xmlXPathNextChild:
5124 * @ctxt: the XPath Parser context
5125 * @cur: the current node in the traversal
5126 *
5127 * Traversal function for the "child" direction
5128 * The child axis contains the children of the context node in document order.
5129 *
5130 * Returns the next element following that axis
5131 */
5132xmlNodePtr
5133xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5134 if (cur == NULL) {
5135 if (ctxt->context->node == NULL) return(NULL);
5136 switch (ctxt->context->node->type) {
5137 case XML_ELEMENT_NODE:
5138 case XML_TEXT_NODE:
5139 case XML_CDATA_SECTION_NODE:
5140 case XML_ENTITY_REF_NODE:
5141 case XML_ENTITY_NODE:
5142 case XML_PI_NODE:
5143 case XML_COMMENT_NODE:
5144 case XML_NOTATION_NODE:
5145 case XML_DTD_NODE:
5146 return(ctxt->context->node->children);
5147 case XML_DOCUMENT_NODE:
5148 case XML_DOCUMENT_TYPE_NODE:
5149 case XML_DOCUMENT_FRAG_NODE:
5150 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005151#ifdef LIBXML_DOCB_ENABLED
5152 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005153#endif
5154 return(((xmlDocPtr) ctxt->context->node)->children);
5155 case XML_ELEMENT_DECL:
5156 case XML_ATTRIBUTE_DECL:
5157 case XML_ENTITY_DECL:
5158 case XML_ATTRIBUTE_NODE:
5159 case XML_NAMESPACE_DECL:
5160 case XML_XINCLUDE_START:
5161 case XML_XINCLUDE_END:
5162 return(NULL);
5163 }
5164 return(NULL);
5165 }
5166 if ((cur->type == XML_DOCUMENT_NODE) ||
5167 (cur->type == XML_HTML_DOCUMENT_NODE))
5168 return(NULL);
5169 return(cur->next);
5170}
5171
5172/**
5173 * xmlXPathNextDescendant:
5174 * @ctxt: the XPath Parser context
5175 * @cur: the current node in the traversal
5176 *
5177 * Traversal function for the "descendant" direction
5178 * the descendant axis contains the descendants of the context node in document
5179 * order; a descendant is a child or a child of a child and so on.
5180 *
5181 * Returns the next element following that axis
5182 */
5183xmlNodePtr
5184xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5185 if (cur == NULL) {
5186 if (ctxt->context->node == NULL)
5187 return(NULL);
5188 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5189 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5190 return(NULL);
5191
5192 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5193 return(ctxt->context->doc->children);
5194 return(ctxt->context->node->children);
5195 }
5196
Daniel Veillard567e1b42001-08-01 15:53:47 +00005197 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00005198 /*
5199 * Do not descend on entities declarations
5200 */
5201 if (cur->children->type != XML_ENTITY_DECL) {
5202 cur = cur->children;
5203 /*
5204 * Skip DTDs
5205 */
5206 if (cur->type != XML_DTD_NODE)
5207 return(cur);
5208 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00005209 }
5210
5211 if (cur == ctxt->context->node) return(NULL);
5212
Daniel Veillard68e9e742002-11-16 15:35:11 +00005213 while (cur->next != NULL) {
5214 cur = cur->next;
5215 if ((cur->type != XML_ENTITY_DECL) &&
5216 (cur->type != XML_DTD_NODE))
5217 return(cur);
5218 }
Owen Taylor3473f882001-02-23 17:55:21 +00005219
5220 do {
5221 cur = cur->parent;
5222 if (cur == NULL) return(NULL);
5223 if (cur == ctxt->context->node) return(NULL);
5224 if (cur->next != NULL) {
5225 cur = cur->next;
5226 return(cur);
5227 }
5228 } while (cur != NULL);
5229 return(cur);
5230}
5231
5232/**
5233 * xmlXPathNextDescendantOrSelf:
5234 * @ctxt: the XPath Parser context
5235 * @cur: the current node in the traversal
5236 *
5237 * Traversal function for the "descendant-or-self" direction
5238 * the descendant-or-self axis contains the context node and the descendants
5239 * of the context node in document order; thus the context node is the first
5240 * node on the axis, and the first child of the context node is the second node
5241 * on the axis
5242 *
5243 * Returns the next element following that axis
5244 */
5245xmlNodePtr
5246xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5247 if (cur == NULL) {
5248 if (ctxt->context->node == NULL)
5249 return(NULL);
5250 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5251 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5252 return(NULL);
5253 return(ctxt->context->node);
5254 }
5255
5256 return(xmlXPathNextDescendant(ctxt, cur));
5257}
5258
5259/**
5260 * xmlXPathNextParent:
5261 * @ctxt: the XPath Parser context
5262 * @cur: the current node in the traversal
5263 *
5264 * Traversal function for the "parent" direction
5265 * The parent axis contains the parent of the context node, if there is one.
5266 *
5267 * Returns the next element following that axis
5268 */
5269xmlNodePtr
5270xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5271 /*
5272 * the parent of an attribute or namespace node is the element
5273 * to which the attribute or namespace node is attached
5274 * Namespace handling !!!
5275 */
5276 if (cur == NULL) {
5277 if (ctxt->context->node == NULL) return(NULL);
5278 switch (ctxt->context->node->type) {
5279 case XML_ELEMENT_NODE:
5280 case XML_TEXT_NODE:
5281 case XML_CDATA_SECTION_NODE:
5282 case XML_ENTITY_REF_NODE:
5283 case XML_ENTITY_NODE:
5284 case XML_PI_NODE:
5285 case XML_COMMENT_NODE:
5286 case XML_NOTATION_NODE:
5287 case XML_DTD_NODE:
5288 case XML_ELEMENT_DECL:
5289 case XML_ATTRIBUTE_DECL:
5290 case XML_XINCLUDE_START:
5291 case XML_XINCLUDE_END:
5292 case XML_ENTITY_DECL:
5293 if (ctxt->context->node->parent == NULL)
5294 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005295 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005296 ((ctxt->context->node->parent->name[0] == ' ') ||
5297 (xmlStrEqual(ctxt->context->node->parent->name,
5298 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005299 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005300 return(ctxt->context->node->parent);
5301 case XML_ATTRIBUTE_NODE: {
5302 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5303
5304 return(att->parent);
5305 }
5306 case XML_DOCUMENT_NODE:
5307 case XML_DOCUMENT_TYPE_NODE:
5308 case XML_DOCUMENT_FRAG_NODE:
5309 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005310#ifdef LIBXML_DOCB_ENABLED
5311 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005312#endif
5313 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005314 case XML_NAMESPACE_DECL: {
5315 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5316
5317 if ((ns->next != NULL) &&
5318 (ns->next->type != XML_NAMESPACE_DECL))
5319 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005320 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005321 }
Owen Taylor3473f882001-02-23 17:55:21 +00005322 }
5323 }
5324 return(NULL);
5325}
5326
5327/**
5328 * xmlXPathNextAncestor:
5329 * @ctxt: the XPath Parser context
5330 * @cur: the current node in the traversal
5331 *
5332 * Traversal function for the "ancestor" direction
5333 * the ancestor axis contains the ancestors of the context node; the ancestors
5334 * of the context node consist of the parent of context node and the parent's
5335 * parent and so on; the nodes are ordered in reverse document order; thus the
5336 * parent is the first node on the axis, and the parent's parent is the second
5337 * node on the axis
5338 *
5339 * Returns the next element following that axis
5340 */
5341xmlNodePtr
5342xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5343 /*
5344 * the parent of an attribute or namespace node is the element
5345 * to which the attribute or namespace node is attached
5346 * !!!!!!!!!!!!!
5347 */
5348 if (cur == NULL) {
5349 if (ctxt->context->node == NULL) return(NULL);
5350 switch (ctxt->context->node->type) {
5351 case XML_ELEMENT_NODE:
5352 case XML_TEXT_NODE:
5353 case XML_CDATA_SECTION_NODE:
5354 case XML_ENTITY_REF_NODE:
5355 case XML_ENTITY_NODE:
5356 case XML_PI_NODE:
5357 case XML_COMMENT_NODE:
5358 case XML_DTD_NODE:
5359 case XML_ELEMENT_DECL:
5360 case XML_ATTRIBUTE_DECL:
5361 case XML_ENTITY_DECL:
5362 case XML_NOTATION_NODE:
5363 case XML_XINCLUDE_START:
5364 case XML_XINCLUDE_END:
5365 if (ctxt->context->node->parent == NULL)
5366 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005367 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005368 ((ctxt->context->node->parent->name[0] == ' ') ||
5369 (xmlStrEqual(ctxt->context->node->parent->name,
5370 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005371 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005372 return(ctxt->context->node->parent);
5373 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005374 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005375
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005376 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005377 }
5378 case XML_DOCUMENT_NODE:
5379 case XML_DOCUMENT_TYPE_NODE:
5380 case XML_DOCUMENT_FRAG_NODE:
5381 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005382#ifdef LIBXML_DOCB_ENABLED
5383 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005384#endif
5385 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005386 case XML_NAMESPACE_DECL: {
5387 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5388
5389 if ((ns->next != NULL) &&
5390 (ns->next->type != XML_NAMESPACE_DECL))
5391 return((xmlNodePtr) ns->next);
5392 /* Bad, how did that namespace ended-up there ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005393 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005394 }
Owen Taylor3473f882001-02-23 17:55:21 +00005395 }
5396 return(NULL);
5397 }
5398 if (cur == ctxt->context->doc->children)
5399 return((xmlNodePtr) ctxt->context->doc);
5400 if (cur == (xmlNodePtr) ctxt->context->doc)
5401 return(NULL);
5402 switch (cur->type) {
5403 case XML_ELEMENT_NODE:
5404 case XML_TEXT_NODE:
5405 case XML_CDATA_SECTION_NODE:
5406 case XML_ENTITY_REF_NODE:
5407 case XML_ENTITY_NODE:
5408 case XML_PI_NODE:
5409 case XML_COMMENT_NODE:
5410 case XML_NOTATION_NODE:
5411 case XML_DTD_NODE:
5412 case XML_ELEMENT_DECL:
5413 case XML_ATTRIBUTE_DECL:
5414 case XML_ENTITY_DECL:
5415 case XML_XINCLUDE_START:
5416 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005417 if (cur->parent == NULL)
5418 return(NULL);
5419 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005420 ((cur->parent->name[0] == ' ') ||
5421 (xmlStrEqual(cur->parent->name,
5422 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005423 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005424 return(cur->parent);
5425 case XML_ATTRIBUTE_NODE: {
5426 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5427
5428 return(att->parent);
5429 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005430 case XML_NAMESPACE_DECL: {
5431 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5432
5433 if ((ns->next != NULL) &&
5434 (ns->next->type != XML_NAMESPACE_DECL))
5435 return((xmlNodePtr) ns->next);
5436 /* Bad, how did that namespace ended-up there ? */
5437 return(NULL);
5438 }
Owen Taylor3473f882001-02-23 17:55:21 +00005439 case XML_DOCUMENT_NODE:
5440 case XML_DOCUMENT_TYPE_NODE:
5441 case XML_DOCUMENT_FRAG_NODE:
5442 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005443#ifdef LIBXML_DOCB_ENABLED
5444 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005445#endif
5446 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005447 }
5448 return(NULL);
5449}
5450
5451/**
5452 * xmlXPathNextAncestorOrSelf:
5453 * @ctxt: the XPath Parser context
5454 * @cur: the current node in the traversal
5455 *
5456 * Traversal function for the "ancestor-or-self" direction
5457 * he ancestor-or-self axis contains the context node and ancestors of
5458 * the context node in reverse document order; thus the context node is
5459 * the first node on the axis, and the context node's parent the second;
5460 * parent here is defined the same as with the parent axis.
5461 *
5462 * Returns the next element following that axis
5463 */
5464xmlNodePtr
5465xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5466 if (cur == NULL)
5467 return(ctxt->context->node);
5468 return(xmlXPathNextAncestor(ctxt, cur));
5469}
5470
5471/**
5472 * xmlXPathNextFollowingSibling:
5473 * @ctxt: the XPath Parser context
5474 * @cur: the current node in the traversal
5475 *
5476 * Traversal function for the "following-sibling" direction
5477 * The following-sibling axis contains the following siblings of the context
5478 * node in document order.
5479 *
5480 * Returns the next element following that axis
5481 */
5482xmlNodePtr
5483xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5484 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5485 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5486 return(NULL);
5487 if (cur == (xmlNodePtr) ctxt->context->doc)
5488 return(NULL);
5489 if (cur == NULL)
5490 return(ctxt->context->node->next);
5491 return(cur->next);
5492}
5493
5494/**
5495 * xmlXPathNextPrecedingSibling:
5496 * @ctxt: the XPath Parser context
5497 * @cur: the current node in the traversal
5498 *
5499 * Traversal function for the "preceding-sibling" direction
5500 * The preceding-sibling axis contains the preceding siblings of the context
5501 * node in reverse document order; the first preceding sibling is first on the
5502 * axis; the sibling preceding that node is the second on the axis and so on.
5503 *
5504 * Returns the next element following that axis
5505 */
5506xmlNodePtr
5507xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5508 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5509 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5510 return(NULL);
5511 if (cur == (xmlNodePtr) ctxt->context->doc)
5512 return(NULL);
5513 if (cur == NULL)
5514 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005515 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5516 cur = cur->prev;
5517 if (cur == NULL)
5518 return(ctxt->context->node->prev);
5519 }
Owen Taylor3473f882001-02-23 17:55:21 +00005520 return(cur->prev);
5521}
5522
5523/**
5524 * xmlXPathNextFollowing:
5525 * @ctxt: the XPath Parser context
5526 * @cur: the current node in the traversal
5527 *
5528 * Traversal function for the "following" direction
5529 * The following axis contains all nodes in the same document as the context
5530 * node that are after the context node in document order, excluding any
5531 * descendants and excluding attribute nodes and namespace nodes; the nodes
5532 * are ordered in document order
5533 *
5534 * Returns the next element following that axis
5535 */
5536xmlNodePtr
5537xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5538 if (cur != NULL && cur->children != NULL)
5539 return cur->children ;
5540 if (cur == NULL) cur = ctxt->context->node;
5541 if (cur == NULL) return(NULL) ; /* ERROR */
5542 if (cur->next != NULL) return(cur->next) ;
5543 do {
5544 cur = cur->parent;
5545 if (cur == NULL) return(NULL);
5546 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5547 if (cur->next != NULL) return(cur->next);
5548 } while (cur != NULL);
5549 return(cur);
5550}
5551
5552/*
5553 * xmlXPathIsAncestor:
5554 * @ancestor: the ancestor node
5555 * @node: the current node
5556 *
5557 * Check that @ancestor is a @node's ancestor
5558 *
5559 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5560 */
5561static int
5562xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5563 if ((ancestor == NULL) || (node == NULL)) return(0);
5564 /* nodes need to be in the same document */
5565 if (ancestor->doc != node->doc) return(0);
5566 /* avoid searching if ancestor or node is the root node */
5567 if (ancestor == (xmlNodePtr) node->doc) return(1);
5568 if (node == (xmlNodePtr) ancestor->doc) return(0);
5569 while (node->parent != NULL) {
5570 if (node->parent == ancestor)
5571 return(1);
5572 node = node->parent;
5573 }
5574 return(0);
5575}
5576
5577/**
5578 * xmlXPathNextPreceding:
5579 * @ctxt: the XPath Parser context
5580 * @cur: the current node in the traversal
5581 *
5582 * Traversal function for the "preceding" direction
5583 * the preceding axis contains all nodes in the same document as the context
5584 * node that are before the context node in document order, excluding any
5585 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5586 * ordered in reverse document order
5587 *
5588 * Returns the next element following that axis
5589 */
5590xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005591xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5592{
Owen Taylor3473f882001-02-23 17:55:21 +00005593 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005594 cur = ctxt->context->node;
5595 if (cur == NULL)
5596 return (NULL);
5597 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5598 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005599 do {
5600 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005601 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5602 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005603 }
5604
5605 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005606 if (cur == NULL)
5607 return (NULL);
5608 if (cur == ctxt->context->doc->children)
5609 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005610 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005611 return (cur);
5612}
5613
5614/**
5615 * xmlXPathNextPrecedingInternal:
5616 * @ctxt: the XPath Parser context
5617 * @cur: the current node in the traversal
5618 *
5619 * Traversal function for the "preceding" direction
5620 * the preceding axis contains all nodes in the same document as the context
5621 * node that are before the context node in document order, excluding any
5622 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5623 * ordered in reverse document order
5624 * This is a faster implementation but internal only since it requires a
5625 * state kept in the parser context: ctxt->ancestor.
5626 *
5627 * Returns the next element following that axis
5628 */
5629static xmlNodePtr
5630xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5631 xmlNodePtr cur)
5632{
5633 if (cur == NULL) {
5634 cur = ctxt->context->node;
5635 if (cur == NULL)
5636 return (NULL);
5637 ctxt->ancestor = cur->parent;
5638 }
5639 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5640 cur = cur->prev;
5641 while (cur->prev == NULL) {
5642 cur = cur->parent;
5643 if (cur == NULL)
5644 return (NULL);
5645 if (cur == ctxt->context->doc->children)
5646 return (NULL);
5647 if (cur != ctxt->ancestor)
5648 return (cur);
5649 ctxt->ancestor = cur->parent;
5650 }
5651 cur = cur->prev;
5652 while (cur->last != NULL)
5653 cur = cur->last;
5654 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005655}
5656
5657/**
5658 * xmlXPathNextNamespace:
5659 * @ctxt: the XPath Parser context
5660 * @cur: the current attribute in the traversal
5661 *
5662 * Traversal function for the "namespace" direction
5663 * the namespace axis contains the namespace nodes of the context node;
5664 * the order of nodes on this axis is implementation-defined; the axis will
5665 * be empty unless the context node is an element
5666 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005667 * We keep the XML namespace node at the end of the list.
5668 *
Owen Taylor3473f882001-02-23 17:55:21 +00005669 * Returns the next element following that axis
5670 */
5671xmlNodePtr
5672xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5673 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00005674 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005675 if (ctxt->context->tmpNsList != NULL)
5676 xmlFree(ctxt->context->tmpNsList);
5677 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005678 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005679 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005680 if (ctxt->context->tmpNsList != NULL) {
5681 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
5682 ctxt->context->tmpNsNr++;
5683 }
5684 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005685 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005686 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00005687 if (ctxt->context->tmpNsNr > 0) {
5688 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
5689 } else {
5690 if (ctxt->context->tmpNsList != NULL)
5691 xmlFree(ctxt->context->tmpNsList);
5692 ctxt->context->tmpNsList = NULL;
5693 return(NULL);
5694 }
Owen Taylor3473f882001-02-23 17:55:21 +00005695}
5696
5697/**
5698 * xmlXPathNextAttribute:
5699 * @ctxt: the XPath Parser context
5700 * @cur: the current attribute in the traversal
5701 *
5702 * Traversal function for the "attribute" direction
5703 * TODO: support DTD inherited default attributes
5704 *
5705 * Returns the next element following that axis
5706 */
5707xmlNodePtr
5708xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005709 if (ctxt->context->node == NULL)
5710 return(NULL);
5711 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5712 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005713 if (cur == NULL) {
5714 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5715 return(NULL);
5716 return((xmlNodePtr)ctxt->context->node->properties);
5717 }
5718 return((xmlNodePtr)cur->next);
5719}
5720
5721/************************************************************************
5722 * *
5723 * NodeTest Functions *
5724 * *
5725 ************************************************************************/
5726
Owen Taylor3473f882001-02-23 17:55:21 +00005727#define IS_FUNCTION 200
5728
Owen Taylor3473f882001-02-23 17:55:21 +00005729
5730/************************************************************************
5731 * *
5732 * Implicit tree core function library *
5733 * *
5734 ************************************************************************/
5735
5736/**
5737 * xmlXPathRoot:
5738 * @ctxt: the XPath Parser context
5739 *
5740 * Initialize the context to the root of the document
5741 */
5742void
5743xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5744 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5745 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5746}
5747
5748/************************************************************************
5749 * *
5750 * The explicit core function library *
5751 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5752 * *
5753 ************************************************************************/
5754
5755
5756/**
5757 * xmlXPathLastFunction:
5758 * @ctxt: the XPath Parser context
5759 * @nargs: the number of arguments
5760 *
5761 * Implement the last() XPath function
5762 * number last()
5763 * The last function returns the number of nodes in the context node list.
5764 */
5765void
5766xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5767 CHECK_ARITY(0);
5768 if (ctxt->context->contextSize >= 0) {
5769 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5770#ifdef DEBUG_EXPR
5771 xmlGenericError(xmlGenericErrorContext,
5772 "last() : %d\n", ctxt->context->contextSize);
5773#endif
5774 } else {
5775 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5776 }
5777}
5778
5779/**
5780 * xmlXPathPositionFunction:
5781 * @ctxt: the XPath Parser context
5782 * @nargs: the number of arguments
5783 *
5784 * Implement the position() XPath function
5785 * number position()
5786 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005787 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00005788 * will be equal to last().
5789 */
5790void
5791xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5792 CHECK_ARITY(0);
5793 if (ctxt->context->proximityPosition >= 0) {
5794 valuePush(ctxt,
5795 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5796#ifdef DEBUG_EXPR
5797 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5798 ctxt->context->proximityPosition);
5799#endif
5800 } else {
5801 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5802 }
5803}
5804
5805/**
5806 * xmlXPathCountFunction:
5807 * @ctxt: the XPath Parser context
5808 * @nargs: the number of arguments
5809 *
5810 * Implement the count() XPath function
5811 * number count(node-set)
5812 */
5813void
5814xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5815 xmlXPathObjectPtr cur;
5816
5817 CHECK_ARITY(1);
5818 if ((ctxt->value == NULL) ||
5819 ((ctxt->value->type != XPATH_NODESET) &&
5820 (ctxt->value->type != XPATH_XSLT_TREE)))
5821 XP_ERROR(XPATH_INVALID_TYPE);
5822 cur = valuePop(ctxt);
5823
Daniel Veillard911f49a2001-04-07 15:39:35 +00005824 if ((cur == NULL) || (cur->nodesetval == NULL))
5825 valuePush(ctxt, xmlXPathNewFloat((double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00005826 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00005827 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00005828 } else {
5829 if ((cur->nodesetval->nodeNr != 1) ||
5830 (cur->nodesetval->nodeTab == NULL)) {
5831 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5832 } else {
5833 xmlNodePtr tmp;
5834 int i = 0;
5835
5836 tmp = cur->nodesetval->nodeTab[0];
5837 if (tmp != NULL) {
5838 tmp = tmp->children;
5839 while (tmp != NULL) {
5840 tmp = tmp->next;
5841 i++;
5842 }
5843 }
5844 valuePush(ctxt, xmlXPathNewFloat((double) i));
5845 }
5846 }
Owen Taylor3473f882001-02-23 17:55:21 +00005847 xmlXPathFreeObject(cur);
5848}
5849
5850/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005851 * xmlXPathGetElementsByIds:
5852 * @doc: the document
5853 * @ids: a whitespace separated list of IDs
5854 *
5855 * Selects elements by their unique ID.
5856 *
5857 * Returns a node-set of selected elements.
5858 */
5859static xmlNodeSetPtr
5860xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5861 xmlNodeSetPtr ret;
5862 const xmlChar *cur = ids;
5863 xmlChar *ID;
5864 xmlAttrPtr attr;
5865 xmlNodePtr elem = NULL;
5866
5867 ret = xmlXPathNodeSetCreate(NULL);
5868
5869 while (IS_BLANK(*cur)) cur++;
5870 while (*cur != 0) {
5871 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
5872 (*cur == '.') || (*cur == '-') ||
5873 (*cur == '_') || (*cur == ':') ||
5874 (IS_COMBINING(*cur)) ||
5875 (IS_EXTENDER(*cur)))
5876 cur++;
5877
5878 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
5879
5880 ID = xmlStrndup(ids, cur - ids);
5881 attr = xmlGetID(doc, ID);
5882 if (attr != NULL) {
5883 elem = attr->parent;
5884 xmlXPathNodeSetAdd(ret, elem);
5885 }
5886 if (ID != NULL)
5887 xmlFree(ID);
5888
5889 while (IS_BLANK(*cur)) cur++;
5890 ids = cur;
5891 }
5892 return(ret);
5893}
5894
5895/**
Owen Taylor3473f882001-02-23 17:55:21 +00005896 * xmlXPathIdFunction:
5897 * @ctxt: the XPath Parser context
5898 * @nargs: the number of arguments
5899 *
5900 * Implement the id() XPath function
5901 * node-set id(object)
5902 * The id function selects elements by their unique ID
5903 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
5904 * then the result is the union of the result of applying id to the
5905 * string value of each of the nodes in the argument node-set. When the
5906 * argument to id is of any other type, the argument is converted to a
5907 * string as if by a call to the string function; the string is split
5908 * into a whitespace-separated list of tokens (whitespace is any sequence
5909 * of characters matching the production S); the result is a node-set
5910 * containing the elements in the same document as the context node that
5911 * have a unique ID equal to any of the tokens in the list.
5912 */
5913void
5914xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005915 xmlChar *tokens;
5916 xmlNodeSetPtr ret;
5917 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00005918
5919 CHECK_ARITY(1);
5920 obj = valuePop(ctxt);
5921 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00005922 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005923 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00005924 int i;
5925
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005926 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005927
Daniel Veillard911f49a2001-04-07 15:39:35 +00005928 if (obj->nodesetval != NULL) {
5929 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005930 tokens =
5931 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
5932 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
5933 ret = xmlXPathNodeSetMerge(ret, ns);
5934 xmlXPathFreeNodeSet(ns);
5935 if (tokens != NULL)
5936 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00005937 }
Owen Taylor3473f882001-02-23 17:55:21 +00005938 }
5939
5940 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005941 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005942 return;
5943 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005944 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00005945
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005946 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
5947 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005948
Owen Taylor3473f882001-02-23 17:55:21 +00005949 xmlXPathFreeObject(obj);
5950 return;
5951}
5952
5953/**
5954 * xmlXPathLocalNameFunction:
5955 * @ctxt: the XPath Parser context
5956 * @nargs: the number of arguments
5957 *
5958 * Implement the local-name() XPath function
5959 * string local-name(node-set?)
5960 * The local-name function returns a string containing the local part
5961 * of the name of the node in the argument node-set that is first in
5962 * document order. If the node-set is empty or the first node has no
5963 * name, an empty string is returned. If the argument is omitted it
5964 * defaults to the context node.
5965 */
5966void
5967xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5968 xmlXPathObjectPtr cur;
5969
5970 if (nargs == 0) {
5971 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5972 nargs = 1;
5973 }
5974
5975 CHECK_ARITY(1);
5976 if ((ctxt->value == NULL) ||
5977 ((ctxt->value->type != XPATH_NODESET) &&
5978 (ctxt->value->type != XPATH_XSLT_TREE)))
5979 XP_ERROR(XPATH_INVALID_TYPE);
5980 cur = valuePop(ctxt);
5981
Daniel Veillard911f49a2001-04-07 15:39:35 +00005982 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005983 valuePush(ctxt, xmlXPathNewCString(""));
5984 } else {
5985 int i = 0; /* Should be first in document order !!!!! */
5986 switch (cur->nodesetval->nodeTab[i]->type) {
5987 case XML_ELEMENT_NODE:
5988 case XML_ATTRIBUTE_NODE:
5989 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00005990 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
5991 valuePush(ctxt, xmlXPathNewCString(""));
5992 else
5993 valuePush(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00005994 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
5995 break;
5996 case XML_NAMESPACE_DECL:
5997 valuePush(ctxt, xmlXPathNewString(
5998 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
5999 break;
6000 default:
6001 valuePush(ctxt, xmlXPathNewCString(""));
6002 }
6003 }
6004 xmlXPathFreeObject(cur);
6005}
6006
6007/**
6008 * xmlXPathNamespaceURIFunction:
6009 * @ctxt: the XPath Parser context
6010 * @nargs: the number of arguments
6011 *
6012 * Implement the namespace-uri() XPath function
6013 * string namespace-uri(node-set?)
6014 * The namespace-uri function returns a string containing the
6015 * namespace URI of the expanded name of the node in the argument
6016 * node-set that is first in document order. If the node-set is empty,
6017 * the first node has no name, or the expanded name has no namespace
6018 * URI, an empty string is returned. If the argument is omitted it
6019 * defaults to the context node.
6020 */
6021void
6022xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6023 xmlXPathObjectPtr cur;
6024
6025 if (nargs == 0) {
6026 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6027 nargs = 1;
6028 }
6029 CHECK_ARITY(1);
6030 if ((ctxt->value == NULL) ||
6031 ((ctxt->value->type != XPATH_NODESET) &&
6032 (ctxt->value->type != XPATH_XSLT_TREE)))
6033 XP_ERROR(XPATH_INVALID_TYPE);
6034 cur = valuePop(ctxt);
6035
Daniel Veillard911f49a2001-04-07 15:39:35 +00006036 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006037 valuePush(ctxt, xmlXPathNewCString(""));
6038 } else {
6039 int i = 0; /* Should be first in document order !!!!! */
6040 switch (cur->nodesetval->nodeTab[i]->type) {
6041 case XML_ELEMENT_NODE:
6042 case XML_ATTRIBUTE_NODE:
6043 if (cur->nodesetval->nodeTab[i]->ns == NULL)
6044 valuePush(ctxt, xmlXPathNewCString(""));
6045 else
6046 valuePush(ctxt, xmlXPathNewString(
6047 cur->nodesetval->nodeTab[i]->ns->href));
6048 break;
6049 default:
6050 valuePush(ctxt, xmlXPathNewCString(""));
6051 }
6052 }
6053 xmlXPathFreeObject(cur);
6054}
6055
6056/**
6057 * xmlXPathNameFunction:
6058 * @ctxt: the XPath Parser context
6059 * @nargs: the number of arguments
6060 *
6061 * Implement the name() XPath function
6062 * string name(node-set?)
6063 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006064 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00006065 * order. The QName must represent the name with respect to the namespace
6066 * declarations in effect on the node whose name is being represented.
6067 * Typically, this will be the form in which the name occurred in the XML
6068 * source. This need not be the case if there are namespace declarations
6069 * in effect on the node that associate multiple prefixes with the same
6070 * namespace. However, an implementation may include information about
6071 * the original prefix in its representation of nodes; in this case, an
6072 * implementation can ensure that the returned string is always the same
6073 * as the QName used in the XML source. If the argument it omitted it
6074 * defaults to the context node.
6075 * Libxml keep the original prefix so the "real qualified name" used is
6076 * returned.
6077 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006078static void
Daniel Veillard04383752001-07-08 14:27:15 +00006079xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
6080{
Owen Taylor3473f882001-02-23 17:55:21 +00006081 xmlXPathObjectPtr cur;
6082
6083 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00006084 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6085 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006086 }
6087
6088 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00006089 if ((ctxt->value == NULL) ||
6090 ((ctxt->value->type != XPATH_NODESET) &&
6091 (ctxt->value->type != XPATH_XSLT_TREE)))
6092 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006093 cur = valuePop(ctxt);
6094
Daniel Veillard911f49a2001-04-07 15:39:35 +00006095 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006096 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00006097 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006098 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00006099
Daniel Veillard04383752001-07-08 14:27:15 +00006100 switch (cur->nodesetval->nodeTab[i]->type) {
6101 case XML_ELEMENT_NODE:
6102 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006103 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6104 valuePush(ctxt, xmlXPathNewCString(""));
6105 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6106 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006107 valuePush(ctxt,
6108 xmlXPathNewString(cur->nodesetval->
6109 nodeTab[i]->name));
6110
Daniel Veillard652d8a92003-02-04 19:28:49 +00006111 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006112 char name[2000];
6113
6114 snprintf(name, sizeof(name), "%s:%s",
6115 (char *) cur->nodesetval->nodeTab[i]->ns->
6116 prefix,
6117 (char *) cur->nodesetval->nodeTab[i]->name);
6118 name[sizeof(name) - 1] = 0;
6119 valuePush(ctxt, xmlXPathNewCString(name));
6120 }
6121 break;
6122 default:
6123 valuePush(ctxt,
6124 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6125 xmlXPathLocalNameFunction(ctxt, 1);
6126 }
Owen Taylor3473f882001-02-23 17:55:21 +00006127 }
6128 xmlXPathFreeObject(cur);
6129}
6130
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006131
6132/**
Owen Taylor3473f882001-02-23 17:55:21 +00006133 * xmlXPathStringFunction:
6134 * @ctxt: the XPath Parser context
6135 * @nargs: the number of arguments
6136 *
6137 * Implement the string() XPath function
6138 * string string(object?)
6139 * he string function converts an object to a string as follows:
6140 * - A node-set is converted to a string by returning the value of
6141 * the node in the node-set that is first in document order.
6142 * If the node-set is empty, an empty string is returned.
6143 * - A number is converted to a string as follows
6144 * + NaN is converted to the string NaN
6145 * + positive zero is converted to the string 0
6146 * + negative zero is converted to the string 0
6147 * + positive infinity is converted to the string Infinity
6148 * + negative infinity is converted to the string -Infinity
6149 * + if the number is an integer, the number is represented in
6150 * decimal form as a Number with no decimal point and no leading
6151 * zeros, preceded by a minus sign (-) if the number is negative
6152 * + otherwise, the number is represented in decimal form as a
6153 * Number including a decimal point with at least one digit
6154 * before the decimal point and at least one digit after the
6155 * decimal point, preceded by a minus sign (-) if the number
6156 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006157 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00006158 * before the decimal point; beyond the one required digit
6159 * after the decimal point there must be as many, but only as
6160 * many, more digits as are needed to uniquely distinguish the
6161 * number from all other IEEE 754 numeric values.
6162 * - The boolean false value is converted to the string false.
6163 * The boolean true value is converted to the string true.
6164 *
6165 * If the argument is omitted, it defaults to a node-set with the
6166 * context node as its only member.
6167 */
6168void
6169xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6170 xmlXPathObjectPtr cur;
6171
6172 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006173 valuePush(ctxt,
6174 xmlXPathWrapString(
6175 xmlXPathCastNodeToString(ctxt->context->node)));
6176 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006177 }
6178
6179 CHECK_ARITY(1);
6180 cur = valuePop(ctxt);
6181 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006182 cur = xmlXPathConvertString(cur);
6183 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006184}
6185
6186/**
6187 * xmlXPathStringLengthFunction:
6188 * @ctxt: the XPath Parser context
6189 * @nargs: the number of arguments
6190 *
6191 * Implement the string-length() XPath function
6192 * number string-length(string?)
6193 * The string-length returns the number of characters in the string
6194 * (see [3.6 Strings]). If the argument is omitted, it defaults to
6195 * the context node converted to a string, in other words the value
6196 * of the context node.
6197 */
6198void
6199xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6200 xmlXPathObjectPtr cur;
6201
6202 if (nargs == 0) {
6203 if (ctxt->context->node == NULL) {
6204 valuePush(ctxt, xmlXPathNewFloat(0));
6205 } else {
6206 xmlChar *content;
6207
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006208 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006209 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00006210 xmlFree(content);
6211 }
6212 return;
6213 }
6214 CHECK_ARITY(1);
6215 CAST_TO_STRING;
6216 CHECK_TYPE(XPATH_STRING);
6217 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006218 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00006219 xmlXPathFreeObject(cur);
6220}
6221
6222/**
6223 * xmlXPathConcatFunction:
6224 * @ctxt: the XPath Parser context
6225 * @nargs: the number of arguments
6226 *
6227 * Implement the concat() XPath function
6228 * string concat(string, string, string*)
6229 * The concat function returns the concatenation of its arguments.
6230 */
6231void
6232xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6233 xmlXPathObjectPtr cur, newobj;
6234 xmlChar *tmp;
6235
6236 if (nargs < 2) {
6237 CHECK_ARITY(2);
6238 }
6239
6240 CAST_TO_STRING;
6241 cur = valuePop(ctxt);
6242 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6243 xmlXPathFreeObject(cur);
6244 return;
6245 }
6246 nargs--;
6247
6248 while (nargs > 0) {
6249 CAST_TO_STRING;
6250 newobj = valuePop(ctxt);
6251 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6252 xmlXPathFreeObject(newobj);
6253 xmlXPathFreeObject(cur);
6254 XP_ERROR(XPATH_INVALID_TYPE);
6255 }
6256 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6257 newobj->stringval = cur->stringval;
6258 cur->stringval = tmp;
6259
6260 xmlXPathFreeObject(newobj);
6261 nargs--;
6262 }
6263 valuePush(ctxt, cur);
6264}
6265
6266/**
6267 * xmlXPathContainsFunction:
6268 * @ctxt: the XPath Parser context
6269 * @nargs: the number of arguments
6270 *
6271 * Implement the contains() XPath function
6272 * boolean contains(string, string)
6273 * The contains function returns true if the first argument string
6274 * contains the second argument string, and otherwise returns false.
6275 */
6276void
6277xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6278 xmlXPathObjectPtr hay, needle;
6279
6280 CHECK_ARITY(2);
6281 CAST_TO_STRING;
6282 CHECK_TYPE(XPATH_STRING);
6283 needle = valuePop(ctxt);
6284 CAST_TO_STRING;
6285 hay = valuePop(ctxt);
6286 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6287 xmlXPathFreeObject(hay);
6288 xmlXPathFreeObject(needle);
6289 XP_ERROR(XPATH_INVALID_TYPE);
6290 }
6291 if (xmlStrstr(hay->stringval, needle->stringval))
6292 valuePush(ctxt, xmlXPathNewBoolean(1));
6293 else
6294 valuePush(ctxt, xmlXPathNewBoolean(0));
6295 xmlXPathFreeObject(hay);
6296 xmlXPathFreeObject(needle);
6297}
6298
6299/**
6300 * xmlXPathStartsWithFunction:
6301 * @ctxt: the XPath Parser context
6302 * @nargs: the number of arguments
6303 *
6304 * Implement the starts-with() XPath function
6305 * boolean starts-with(string, string)
6306 * The starts-with function returns true if the first argument string
6307 * starts with the second argument string, and otherwise returns false.
6308 */
6309void
6310xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6311 xmlXPathObjectPtr hay, needle;
6312 int n;
6313
6314 CHECK_ARITY(2);
6315 CAST_TO_STRING;
6316 CHECK_TYPE(XPATH_STRING);
6317 needle = valuePop(ctxt);
6318 CAST_TO_STRING;
6319 hay = valuePop(ctxt);
6320 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6321 xmlXPathFreeObject(hay);
6322 xmlXPathFreeObject(needle);
6323 XP_ERROR(XPATH_INVALID_TYPE);
6324 }
6325 n = xmlStrlen(needle->stringval);
6326 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6327 valuePush(ctxt, xmlXPathNewBoolean(0));
6328 else
6329 valuePush(ctxt, xmlXPathNewBoolean(1));
6330 xmlXPathFreeObject(hay);
6331 xmlXPathFreeObject(needle);
6332}
6333
6334/**
6335 * xmlXPathSubstringFunction:
6336 * @ctxt: the XPath Parser context
6337 * @nargs: the number of arguments
6338 *
6339 * Implement the substring() XPath function
6340 * string substring(string, number, number?)
6341 * The substring function returns the substring of the first argument
6342 * starting at the position specified in the second argument with
6343 * length specified in the third argument. For example,
6344 * substring("12345",2,3) returns "234". If the third argument is not
6345 * specified, it returns the substring starting at the position specified
6346 * in the second argument and continuing to the end of the string. For
6347 * example, substring("12345",2) returns "2345". More precisely, each
6348 * character in the string (see [3.6 Strings]) is considered to have a
6349 * numeric position: the position of the first character is 1, the position
6350 * of the second character is 2 and so on. The returned substring contains
6351 * those characters for which the position of the character is greater than
6352 * or equal to the second argument and, if the third argument is specified,
6353 * less than the sum of the second and third arguments; the comparisons
6354 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6355 * - substring("12345", 1.5, 2.6) returns "234"
6356 * - substring("12345", 0, 3) returns "12"
6357 * - substring("12345", 0 div 0, 3) returns ""
6358 * - substring("12345", 1, 0 div 0) returns ""
6359 * - substring("12345", -42, 1 div 0) returns "12345"
6360 * - substring("12345", -1 div 0, 1 div 0) returns ""
6361 */
6362void
6363xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6364 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006365 double le=0, in;
6366 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006367 xmlChar *ret;
6368
Owen Taylor3473f882001-02-23 17:55:21 +00006369 if (nargs < 2) {
6370 CHECK_ARITY(2);
6371 }
6372 if (nargs > 3) {
6373 CHECK_ARITY(3);
6374 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006375 /*
6376 * take care of possible last (position) argument
6377 */
Owen Taylor3473f882001-02-23 17:55:21 +00006378 if (nargs == 3) {
6379 CAST_TO_NUMBER;
6380 CHECK_TYPE(XPATH_NUMBER);
6381 len = valuePop(ctxt);
6382 le = len->floatval;
6383 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006384 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006385
Owen Taylor3473f882001-02-23 17:55:21 +00006386 CAST_TO_NUMBER;
6387 CHECK_TYPE(XPATH_NUMBER);
6388 start = valuePop(ctxt);
6389 in = start->floatval;
6390 xmlXPathFreeObject(start);
6391 CAST_TO_STRING;
6392 CHECK_TYPE(XPATH_STRING);
6393 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006394 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006395
Daniel Veillard97ac1312001-05-30 19:14:17 +00006396 /*
6397 * If last pos not present, calculate last position
6398 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006399 if (nargs != 3) {
6400 le = (double)m;
6401 if (in < 1.0)
6402 in = 1.0;
6403 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006404
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006405 /* Need to check for the special cases where either
6406 * the index is NaN, the length is NaN, or both
6407 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00006408 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006409 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006410 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00006411 * To meet the requirements of the spec, the arguments
6412 * must be converted to integer format before
6413 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006414 *
Daniel Veillard9e412302002-06-10 15:59:44 +00006415 * First we go to integer form, rounding up
6416 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006417 */
6418 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00006419 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00006420
Daniel Veillard9e412302002-06-10 15:59:44 +00006421 if (xmlXPathIsInf(le) == 1) {
6422 l = m;
6423 if (i < 1)
6424 i = 1;
6425 }
6426 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
6427 l = 0;
6428 else {
6429 l = (int) le;
6430 if (((double)l)+0.5 <= le) l++;
6431 }
6432
6433 /* Now we normalize inidices */
6434 i -= 1;
6435 l += i;
6436 if (i < 0)
6437 i = 0;
6438 if (l > m)
6439 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00006440
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006441 /* number of chars to copy */
6442 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00006443
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006444 ret = xmlUTF8Strsub(str->stringval, i, l);
6445 }
6446 else {
6447 ret = NULL;
6448 }
6449
Owen Taylor3473f882001-02-23 17:55:21 +00006450 if (ret == NULL)
6451 valuePush(ctxt, xmlXPathNewCString(""));
6452 else {
6453 valuePush(ctxt, xmlXPathNewString(ret));
6454 xmlFree(ret);
6455 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006456
Owen Taylor3473f882001-02-23 17:55:21 +00006457 xmlXPathFreeObject(str);
6458}
6459
6460/**
6461 * xmlXPathSubstringBeforeFunction:
6462 * @ctxt: the XPath Parser context
6463 * @nargs: the number of arguments
6464 *
6465 * Implement the substring-before() XPath function
6466 * string substring-before(string, string)
6467 * The substring-before function returns the substring of the first
6468 * argument string that precedes the first occurrence of the second
6469 * argument string in the first argument string, or the empty string
6470 * if the first argument string does not contain the second argument
6471 * string. For example, substring-before("1999/04/01","/") returns 1999.
6472 */
6473void
6474xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6475 xmlXPathObjectPtr str;
6476 xmlXPathObjectPtr find;
6477 xmlBufferPtr target;
6478 const xmlChar *point;
6479 int offset;
6480
6481 CHECK_ARITY(2);
6482 CAST_TO_STRING;
6483 find = valuePop(ctxt);
6484 CAST_TO_STRING;
6485 str = valuePop(ctxt);
6486
6487 target = xmlBufferCreate();
6488 if (target) {
6489 point = xmlStrstr(str->stringval, find->stringval);
6490 if (point) {
6491 offset = (int)(point - str->stringval);
6492 xmlBufferAdd(target, str->stringval, offset);
6493 }
6494 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6495 xmlBufferFree(target);
6496 }
6497
6498 xmlXPathFreeObject(str);
6499 xmlXPathFreeObject(find);
6500}
6501
6502/**
6503 * xmlXPathSubstringAfterFunction:
6504 * @ctxt: the XPath Parser context
6505 * @nargs: the number of arguments
6506 *
6507 * Implement the substring-after() XPath function
6508 * string substring-after(string, string)
6509 * The substring-after function returns the substring of the first
6510 * argument string that follows the first occurrence of the second
6511 * argument string in the first argument string, or the empty stringi
6512 * if the first argument string does not contain the second argument
6513 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6514 * and substring-after("1999/04/01","19") returns 99/04/01.
6515 */
6516void
6517xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6518 xmlXPathObjectPtr str;
6519 xmlXPathObjectPtr find;
6520 xmlBufferPtr target;
6521 const xmlChar *point;
6522 int offset;
6523
6524 CHECK_ARITY(2);
6525 CAST_TO_STRING;
6526 find = valuePop(ctxt);
6527 CAST_TO_STRING;
6528 str = valuePop(ctxt);
6529
6530 target = xmlBufferCreate();
6531 if (target) {
6532 point = xmlStrstr(str->stringval, find->stringval);
6533 if (point) {
6534 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6535 xmlBufferAdd(target, &str->stringval[offset],
6536 xmlStrlen(str->stringval) - offset);
6537 }
6538 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6539 xmlBufferFree(target);
6540 }
6541
6542 xmlXPathFreeObject(str);
6543 xmlXPathFreeObject(find);
6544}
6545
6546/**
6547 * xmlXPathNormalizeFunction:
6548 * @ctxt: the XPath Parser context
6549 * @nargs: the number of arguments
6550 *
6551 * Implement the normalize-space() XPath function
6552 * string normalize-space(string?)
6553 * The normalize-space function returns the argument string with white
6554 * space normalized by stripping leading and trailing whitespace
6555 * and replacing sequences of whitespace characters by a single
6556 * space. Whitespace characters are the same allowed by the S production
6557 * in XML. If the argument is omitted, it defaults to the context
6558 * node converted to a string, in other words the value of the context node.
6559 */
6560void
6561xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6562 xmlXPathObjectPtr obj = NULL;
6563 xmlChar *source = NULL;
6564 xmlBufferPtr target;
6565 xmlChar blank;
6566
6567 if (nargs == 0) {
6568 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006569 valuePush(ctxt,
6570 xmlXPathWrapString(
6571 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006572 nargs = 1;
6573 }
6574
6575 CHECK_ARITY(1);
6576 CAST_TO_STRING;
6577 CHECK_TYPE(XPATH_STRING);
6578 obj = valuePop(ctxt);
6579 source = obj->stringval;
6580
6581 target = xmlBufferCreate();
6582 if (target && source) {
6583
6584 /* Skip leading whitespaces */
6585 while (IS_BLANK(*source))
6586 source++;
6587
6588 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6589 blank = 0;
6590 while (*source) {
6591 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006592 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006593 } else {
6594 if (blank) {
6595 xmlBufferAdd(target, &blank, 1);
6596 blank = 0;
6597 }
6598 xmlBufferAdd(target, source, 1);
6599 }
6600 source++;
6601 }
6602
6603 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6604 xmlBufferFree(target);
6605 }
6606 xmlXPathFreeObject(obj);
6607}
6608
6609/**
6610 * xmlXPathTranslateFunction:
6611 * @ctxt: the XPath Parser context
6612 * @nargs: the number of arguments
6613 *
6614 * Implement the translate() XPath function
6615 * string translate(string, string, string)
6616 * The translate function returns the first argument string with
6617 * occurrences of characters in the second argument string replaced
6618 * by the character at the corresponding position in the third argument
6619 * string. For example, translate("bar","abc","ABC") returns the string
6620 * BAr. If there is a character in the second argument string with no
6621 * character at a corresponding position in the third argument string
6622 * (because the second argument string is longer than the third argument
6623 * string), then occurrences of that character in the first argument
6624 * string are removed. For example, translate("--aaa--","abc-","ABC")
6625 * returns "AAA". If a character occurs more than once in second
6626 * argument string, then the first occurrence determines the replacement
6627 * character. If the third argument string is longer than the second
6628 * argument string, then excess characters are ignored.
6629 */
6630void
6631xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006632 xmlXPathObjectPtr str;
6633 xmlXPathObjectPtr from;
6634 xmlXPathObjectPtr to;
6635 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006636 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006637 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006638 xmlChar *point;
6639 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006640
Daniel Veillarde043ee12001-04-16 14:08:07 +00006641 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006642
Daniel Veillarde043ee12001-04-16 14:08:07 +00006643 CAST_TO_STRING;
6644 to = valuePop(ctxt);
6645 CAST_TO_STRING;
6646 from = valuePop(ctxt);
6647 CAST_TO_STRING;
6648 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006649
Daniel Veillarde043ee12001-04-16 14:08:07 +00006650 target = xmlBufferCreate();
6651 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006652 max = xmlUTF8Strlen(to->stringval);
6653 for (cptr = str->stringval; (ch=*cptr); ) {
6654 offset = xmlUTF8Strloc(from->stringval, cptr);
6655 if (offset >= 0) {
6656 if (offset < max) {
6657 point = xmlUTF8Strpos(to->stringval, offset);
6658 if (point)
6659 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6660 }
6661 } else
6662 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6663
6664 /* Step to next character in input */
6665 cptr++;
6666 if ( ch & 0x80 ) {
6667 /* if not simple ascii, verify proper format */
6668 if ( (ch & 0xc0) != 0xc0 ) {
6669 xmlGenericError(xmlGenericErrorContext,
6670 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6671 break;
6672 }
6673 /* then skip over remaining bytes for this char */
6674 while ( (ch <<= 1) & 0x80 )
6675 if ( (*cptr++ & 0xc0) != 0x80 ) {
6676 xmlGenericError(xmlGenericErrorContext,
6677 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6678 break;
6679 }
6680 if (ch & 0x80) /* must have had error encountered */
6681 break;
6682 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006683 }
Owen Taylor3473f882001-02-23 17:55:21 +00006684 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006685 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6686 xmlBufferFree(target);
6687 xmlXPathFreeObject(str);
6688 xmlXPathFreeObject(from);
6689 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006690}
6691
6692/**
6693 * xmlXPathBooleanFunction:
6694 * @ctxt: the XPath Parser context
6695 * @nargs: the number of arguments
6696 *
6697 * Implement the boolean() XPath function
6698 * boolean boolean(object)
6699 * he boolean function converts its argument to a boolean as follows:
6700 * - a number is true if and only if it is neither positive or
6701 * negative zero nor NaN
6702 * - a node-set is true if and only if it is non-empty
6703 * - a string is true if and only if its length is non-zero
6704 */
6705void
6706xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6707 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006708
6709 CHECK_ARITY(1);
6710 cur = valuePop(ctxt);
6711 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006712 cur = xmlXPathConvertBoolean(cur);
6713 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006714}
6715
6716/**
6717 * xmlXPathNotFunction:
6718 * @ctxt: the XPath Parser context
6719 * @nargs: the number of arguments
6720 *
6721 * Implement the not() XPath function
6722 * boolean not(boolean)
6723 * The not function returns true if its argument is false,
6724 * and false otherwise.
6725 */
6726void
6727xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6728 CHECK_ARITY(1);
6729 CAST_TO_BOOLEAN;
6730 CHECK_TYPE(XPATH_BOOLEAN);
6731 ctxt->value->boolval = ! ctxt->value->boolval;
6732}
6733
6734/**
6735 * xmlXPathTrueFunction:
6736 * @ctxt: the XPath Parser context
6737 * @nargs: the number of arguments
6738 *
6739 * Implement the true() XPath function
6740 * boolean true()
6741 */
6742void
6743xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6744 CHECK_ARITY(0);
6745 valuePush(ctxt, xmlXPathNewBoolean(1));
6746}
6747
6748/**
6749 * xmlXPathFalseFunction:
6750 * @ctxt: the XPath Parser context
6751 * @nargs: the number of arguments
6752 *
6753 * Implement the false() XPath function
6754 * boolean false()
6755 */
6756void
6757xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6758 CHECK_ARITY(0);
6759 valuePush(ctxt, xmlXPathNewBoolean(0));
6760}
6761
6762/**
6763 * xmlXPathLangFunction:
6764 * @ctxt: the XPath Parser context
6765 * @nargs: the number of arguments
6766 *
6767 * Implement the lang() XPath function
6768 * boolean lang(string)
6769 * The lang function returns true or false depending on whether the
6770 * language of the context node as specified by xml:lang attributes
6771 * is the same as or is a sublanguage of the language specified by
6772 * the argument string. The language of the context node is determined
6773 * by the value of the xml:lang attribute on the context node, or, if
6774 * the context node has no xml:lang attribute, by the value of the
6775 * xml:lang attribute on the nearest ancestor of the context node that
6776 * has an xml:lang attribute. If there is no such attribute, then lang
6777 * returns false. If there is such an attribute, then lang returns
6778 * true if the attribute value is equal to the argument ignoring case,
6779 * or if there is some suffix starting with - such that the attribute
6780 * value is equal to the argument ignoring that suffix of the attribute
6781 * value and ignoring case.
6782 */
6783void
6784xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6785 xmlXPathObjectPtr val;
6786 const xmlChar *theLang;
6787 const xmlChar *lang;
6788 int ret = 0;
6789 int i;
6790
6791 CHECK_ARITY(1);
6792 CAST_TO_STRING;
6793 CHECK_TYPE(XPATH_STRING);
6794 val = valuePop(ctxt);
6795 lang = val->stringval;
6796 theLang = xmlNodeGetLang(ctxt->context->node);
6797 if ((theLang != NULL) && (lang != NULL)) {
6798 for (i = 0;lang[i] != 0;i++)
6799 if (toupper(lang[i]) != toupper(theLang[i]))
6800 goto not_equal;
6801 ret = 1;
6802 }
6803not_equal:
6804 xmlXPathFreeObject(val);
6805 valuePush(ctxt, xmlXPathNewBoolean(ret));
6806}
6807
6808/**
6809 * xmlXPathNumberFunction:
6810 * @ctxt: the XPath Parser context
6811 * @nargs: the number of arguments
6812 *
6813 * Implement the number() XPath function
6814 * number number(object?)
6815 */
6816void
6817xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6818 xmlXPathObjectPtr cur;
6819 double res;
6820
6821 if (nargs == 0) {
6822 if (ctxt->context->node == NULL) {
6823 valuePush(ctxt, xmlXPathNewFloat(0.0));
6824 } else {
6825 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6826
6827 res = xmlXPathStringEvalNumber(content);
6828 valuePush(ctxt, xmlXPathNewFloat(res));
6829 xmlFree(content);
6830 }
6831 return;
6832 }
6833
6834 CHECK_ARITY(1);
6835 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006836 cur = xmlXPathConvertNumber(cur);
6837 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006838}
6839
6840/**
6841 * xmlXPathSumFunction:
6842 * @ctxt: the XPath Parser context
6843 * @nargs: the number of arguments
6844 *
6845 * Implement the sum() XPath function
6846 * number sum(node-set)
6847 * The sum function returns the sum of the values of the nodes in
6848 * the argument node-set.
6849 */
6850void
6851xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6852 xmlXPathObjectPtr cur;
6853 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006854 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00006855
6856 CHECK_ARITY(1);
6857 if ((ctxt->value == NULL) ||
6858 ((ctxt->value->type != XPATH_NODESET) &&
6859 (ctxt->value->type != XPATH_XSLT_TREE)))
6860 XP_ERROR(XPATH_INVALID_TYPE);
6861 cur = valuePop(ctxt);
6862
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006863 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006864 valuePush(ctxt, xmlXPathNewFloat(0.0));
6865 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006866 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
6867 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006868 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006869 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00006870 }
6871 xmlXPathFreeObject(cur);
6872}
6873
6874/**
6875 * xmlXPathFloorFunction:
6876 * @ctxt: the XPath Parser context
6877 * @nargs: the number of arguments
6878 *
6879 * Implement the floor() XPath function
6880 * number floor(number)
6881 * The floor function returns the largest (closest to positive infinity)
6882 * number that is not greater than the argument and that is an integer.
6883 */
6884void
6885xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006886 double f;
6887
Owen Taylor3473f882001-02-23 17:55:21 +00006888 CHECK_ARITY(1);
6889 CAST_TO_NUMBER;
6890 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006891
6892 f = (double)((int) ctxt->value->floatval);
6893 if (f != ctxt->value->floatval) {
6894 if (ctxt->value->floatval > 0)
6895 ctxt->value->floatval = f;
6896 else
6897 ctxt->value->floatval = f - 1;
6898 }
Owen Taylor3473f882001-02-23 17:55:21 +00006899}
6900
6901/**
6902 * xmlXPathCeilingFunction:
6903 * @ctxt: the XPath Parser context
6904 * @nargs: the number of arguments
6905 *
6906 * Implement the ceiling() XPath function
6907 * number ceiling(number)
6908 * The ceiling function returns the smallest (closest to negative infinity)
6909 * number that is not less than the argument and that is an integer.
6910 */
6911void
6912xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6913 double f;
6914
6915 CHECK_ARITY(1);
6916 CAST_TO_NUMBER;
6917 CHECK_TYPE(XPATH_NUMBER);
6918
6919#if 0
6920 ctxt->value->floatval = ceil(ctxt->value->floatval);
6921#else
6922 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006923 if (f != ctxt->value->floatval) {
6924 if (ctxt->value->floatval > 0)
6925 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00006926 else {
6927 if (ctxt->value->floatval < 0 && f == 0)
6928 ctxt->value->floatval = xmlXPathNZERO;
6929 else
6930 ctxt->value->floatval = f;
6931 }
6932
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006933 }
Owen Taylor3473f882001-02-23 17:55:21 +00006934#endif
6935}
6936
6937/**
6938 * xmlXPathRoundFunction:
6939 * @ctxt: the XPath Parser context
6940 * @nargs: the number of arguments
6941 *
6942 * Implement the round() XPath function
6943 * number round(number)
6944 * The round function returns the number that is closest to the
6945 * argument and that is an integer. If there are two such numbers,
6946 * then the one that is even is returned.
6947 */
6948void
6949xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6950 double f;
6951
6952 CHECK_ARITY(1);
6953 CAST_TO_NUMBER;
6954 CHECK_TYPE(XPATH_NUMBER);
6955
Daniel Veillardcda96922001-08-21 10:56:31 +00006956 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
6957 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
6958 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00006959 (ctxt->value->floatval == 0.0))
6960 return;
6961
Owen Taylor3473f882001-02-23 17:55:21 +00006962 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006963 if (ctxt->value->floatval < 0) {
6964 if (ctxt->value->floatval < f - 0.5)
6965 ctxt->value->floatval = f - 1;
6966 else
6967 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00006968 if (ctxt->value->floatval == 0)
6969 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006970 } else {
6971 if (ctxt->value->floatval < f + 0.5)
6972 ctxt->value->floatval = f;
6973 else
6974 ctxt->value->floatval = f + 1;
6975 }
Owen Taylor3473f882001-02-23 17:55:21 +00006976}
6977
6978/************************************************************************
6979 * *
6980 * The Parser *
6981 * *
6982 ************************************************************************/
6983
6984/*
6985 * a couple of forward declarations since we use a recursive call based
6986 * implementation.
6987 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006988static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006989static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006990static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006991static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00006992static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
6993 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00006994
6995/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00006996 * xmlXPathCurrentChar:
6997 * @ctxt: the XPath parser context
6998 * @cur: pointer to the beginning of the char
6999 * @len: pointer to the length of the char read
7000 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007001 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00007002 * bytes in the input buffer.
7003 *
Daniel Veillard60087f32001-10-10 09:45:09 +00007004 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00007005 */
7006
7007static int
7008xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
7009 unsigned char c;
7010 unsigned int val;
7011 const xmlChar *cur;
7012
7013 if (ctxt == NULL)
7014 return(0);
7015 cur = ctxt->cur;
7016
7017 /*
7018 * We are supposed to handle UTF8, check it's valid
7019 * From rfc2044: encoding of the Unicode values on UTF-8:
7020 *
7021 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
7022 * 0000 0000-0000 007F 0xxxxxxx
7023 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
7024 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
7025 *
7026 * Check for the 0x110000 limit too
7027 */
7028 c = *cur;
7029 if (c & 0x80) {
7030 if ((cur[1] & 0xc0) != 0x80)
7031 goto encoding_error;
7032 if ((c & 0xe0) == 0xe0) {
7033
7034 if ((cur[2] & 0xc0) != 0x80)
7035 goto encoding_error;
7036 if ((c & 0xf0) == 0xf0) {
7037 if (((c & 0xf8) != 0xf0) ||
7038 ((cur[3] & 0xc0) != 0x80))
7039 goto encoding_error;
7040 /* 4-byte code */
7041 *len = 4;
7042 val = (cur[0] & 0x7) << 18;
7043 val |= (cur[1] & 0x3f) << 12;
7044 val |= (cur[2] & 0x3f) << 6;
7045 val |= cur[3] & 0x3f;
7046 } else {
7047 /* 3-byte code */
7048 *len = 3;
7049 val = (cur[0] & 0xf) << 12;
7050 val |= (cur[1] & 0x3f) << 6;
7051 val |= cur[2] & 0x3f;
7052 }
7053 } else {
7054 /* 2-byte code */
7055 *len = 2;
7056 val = (cur[0] & 0x1f) << 6;
7057 val |= cur[1] & 0x3f;
7058 }
7059 if (!IS_CHAR(val)) {
7060 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
7061 }
7062 return(val);
7063 } else {
7064 /* 1-byte code */
7065 *len = 1;
7066 return((int) *cur);
7067 }
7068encoding_error:
7069 /*
7070 * If we detect an UTF8 error that probably mean that the
7071 * input encoding didn't get properly advertized in the
7072 * declaration header. Report the error and switch the encoding
7073 * to ISO-Latin-1 (if you don't like this policy, just declare the
7074 * encoding !)
7075 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00007076 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00007077 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007078}
7079
7080/**
Owen Taylor3473f882001-02-23 17:55:21 +00007081 * xmlXPathParseNCName:
7082 * @ctxt: the XPath Parser context
7083 *
7084 * parse an XML namespace non qualified name.
7085 *
7086 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7087 *
7088 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7089 * CombiningChar | Extender
7090 *
7091 * Returns the namespace name or NULL
7092 */
7093
7094xmlChar *
7095xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00007096 const xmlChar *in;
7097 xmlChar *ret;
7098 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007099
Daniel Veillard2156a562001-04-28 12:24:34 +00007100 /*
7101 * Accelerator for simple ASCII names
7102 */
7103 in = ctxt->cur;
7104 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7105 ((*in >= 0x41) && (*in <= 0x5A)) ||
7106 (*in == '_')) {
7107 in++;
7108 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7109 ((*in >= 0x41) && (*in <= 0x5A)) ||
7110 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00007111 (*in == '_') || (*in == '.') ||
7112 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00007113 in++;
7114 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7115 (*in == '[') || (*in == ']') || (*in == ':') ||
7116 (*in == '@') || (*in == '*')) {
7117 count = in - ctxt->cur;
7118 if (count == 0)
7119 return(NULL);
7120 ret = xmlStrndup(ctxt->cur, count);
7121 ctxt->cur = in;
7122 return(ret);
7123 }
7124 }
7125 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00007126}
7127
Daniel Veillard2156a562001-04-28 12:24:34 +00007128
Owen Taylor3473f882001-02-23 17:55:21 +00007129/**
7130 * xmlXPathParseQName:
7131 * @ctxt: the XPath Parser context
7132 * @prefix: a xmlChar **
7133 *
7134 * parse an XML qualified name
7135 *
7136 * [NS 5] QName ::= (Prefix ':')? LocalPart
7137 *
7138 * [NS 6] Prefix ::= NCName
7139 *
7140 * [NS 7] LocalPart ::= NCName
7141 *
7142 * Returns the function returns the local part, and prefix is updated
7143 * to get the Prefix if any.
7144 */
7145
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007146static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007147xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7148 xmlChar *ret = NULL;
7149
7150 *prefix = NULL;
7151 ret = xmlXPathParseNCName(ctxt);
7152 if (CUR == ':') {
7153 *prefix = ret;
7154 NEXT;
7155 ret = xmlXPathParseNCName(ctxt);
7156 }
7157 return(ret);
7158}
7159
7160/**
7161 * xmlXPathParseName:
7162 * @ctxt: the XPath Parser context
7163 *
7164 * parse an XML name
7165 *
7166 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7167 * CombiningChar | Extender
7168 *
7169 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7170 *
7171 * Returns the namespace name or NULL
7172 */
7173
7174xmlChar *
7175xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007176 const xmlChar *in;
7177 xmlChar *ret;
7178 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007179
Daniel Veillard61d80a22001-04-27 17:13:01 +00007180 /*
7181 * Accelerator for simple ASCII names
7182 */
7183 in = ctxt->cur;
7184 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7185 ((*in >= 0x41) && (*in <= 0x5A)) ||
7186 (*in == '_') || (*in == ':')) {
7187 in++;
7188 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7189 ((*in >= 0x41) && (*in <= 0x5A)) ||
7190 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00007191 (*in == '_') || (*in == '-') ||
7192 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00007193 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007194 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007195 count = in - ctxt->cur;
7196 ret = xmlStrndup(ctxt->cur, count);
7197 ctxt->cur = in;
7198 return(ret);
7199 }
7200 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007201 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00007202}
7203
Daniel Veillard61d80a22001-04-27 17:13:01 +00007204static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00007205xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007206 xmlChar buf[XML_MAX_NAMELEN + 5];
7207 int len = 0, l;
7208 int c;
7209
7210 /*
7211 * Handler for more complex cases
7212 */
7213 c = CUR_CHAR(l);
7214 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00007215 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7216 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00007217 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00007218 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007219 return(NULL);
7220 }
7221
7222 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7223 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7224 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007225 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007226 (IS_COMBINING(c)) ||
7227 (IS_EXTENDER(c)))) {
7228 COPY_BUF(l,buf,len,c);
7229 NEXTL(l);
7230 c = CUR_CHAR(l);
7231 if (len >= XML_MAX_NAMELEN) {
7232 /*
7233 * Okay someone managed to make a huge name, so he's ready to pay
7234 * for the processing speed.
7235 */
7236 xmlChar *buffer;
7237 int max = len * 2;
7238
7239 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
7240 if (buffer == NULL) {
7241 XP_ERROR0(XPATH_MEMORY_ERROR);
7242 }
7243 memcpy(buffer, buf, len);
7244 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7245 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007246 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007247 (IS_COMBINING(c)) ||
7248 (IS_EXTENDER(c))) {
7249 if (len + 10 > max) {
7250 max *= 2;
7251 buffer = (xmlChar *) xmlRealloc(buffer,
7252 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007253 if (buffer == NULL) {
7254 XP_ERROR0(XPATH_MEMORY_ERROR);
7255 }
7256 }
7257 COPY_BUF(l,buffer,len,c);
7258 NEXTL(l);
7259 c = CUR_CHAR(l);
7260 }
7261 buffer[len] = 0;
7262 return(buffer);
7263 }
7264 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007265 if (len == 0)
7266 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007267 return(xmlStrndup(buf, len));
7268}
Daniel Veillard3cd72402002-05-13 10:33:30 +00007269
7270#define MAX_FRAC 20
7271
7272static double my_pow10[MAX_FRAC] = {
7273 1.0, 10.0, 100.0, 1000.0, 10000.0,
7274 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7275 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7276 100000000000000.0,
7277 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
7278 1000000000000000000.0, 10000000000000000000.0
7279};
7280
Owen Taylor3473f882001-02-23 17:55:21 +00007281/**
7282 * xmlXPathStringEvalNumber:
7283 * @str: A string to scan
7284 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00007285 * [30a] Float ::= Number ('e' Digits?)?
7286 *
Owen Taylor3473f882001-02-23 17:55:21 +00007287 * [30] Number ::= Digits ('.' Digits?)?
7288 * | '.' Digits
7289 * [31] Digits ::= [0-9]+
7290 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007291 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00007292 * In complement of the Number expression, this function also handles
7293 * negative values : '-' Number.
7294 *
7295 * Returns the double value.
7296 */
7297double
7298xmlXPathStringEvalNumber(const xmlChar *str) {
7299 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00007300 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007301 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007302 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007303 int exponent = 0;
7304 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007305#ifdef __GNUC__
7306 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007307 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007308#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00007309 if (cur == NULL) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00007310 while (IS_BLANK(*cur)) cur++;
7311 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7312 return(xmlXPathNAN);
7313 }
7314 if (*cur == '-') {
7315 isneg = 1;
7316 cur++;
7317 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007318
7319#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007320 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007321 * tmp/temp is a workaround against a gcc compiler bug
7322 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007323 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007324 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007325 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007326 ret = ret * 10;
7327 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00007328 ok = 1;
7329 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00007330 temp = (double) tmp;
7331 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007332 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007333#else
Daniel Veillard7b416132002-03-07 08:36:03 +00007334 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007335 while ((*cur >= '0') && (*cur <= '9')) {
7336 ret = ret * 10 + (*cur - '0');
7337 ok = 1;
7338 cur++;
7339 }
7340#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007341
Owen Taylor3473f882001-02-23 17:55:21 +00007342 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007343 int v, frac = 0;
7344 double fraction = 0;
7345
Owen Taylor3473f882001-02-23 17:55:21 +00007346 cur++;
7347 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7348 return(xmlXPathNAN);
7349 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007350 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
7351 v = (*cur - '0');
7352 fraction = fraction * 10 + v;
7353 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007354 cur++;
7355 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007356 fraction /= my_pow10[frac];
7357 ret = ret + fraction;
7358 while ((*cur >= '0') && (*cur <= '9'))
7359 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007360 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007361 if ((*cur == 'e') || (*cur == 'E')) {
7362 cur++;
7363 if (*cur == '-') {
7364 is_exponent_negative = 1;
7365 cur++;
7366 }
7367 while ((*cur >= '0') && (*cur <= '9')) {
7368 exponent = exponent * 10 + (*cur - '0');
7369 cur++;
7370 }
7371 }
Owen Taylor3473f882001-02-23 17:55:21 +00007372 while (IS_BLANK(*cur)) cur++;
7373 if (*cur != 0) return(xmlXPathNAN);
7374 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007375 if (is_exponent_negative) exponent = -exponent;
7376 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007377 return(ret);
7378}
7379
7380/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007381 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007382 * @ctxt: the XPath Parser context
7383 *
7384 * [30] Number ::= Digits ('.' Digits?)?
7385 * | '.' Digits
7386 * [31] Digits ::= [0-9]+
7387 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007388 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007389 *
7390 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007391static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007392xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7393{
Owen Taylor3473f882001-02-23 17:55:21 +00007394 double ret = 0.0;
7395 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007396 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007397 int exponent = 0;
7398 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007399#ifdef __GNUC__
7400 unsigned long tmp = 0;
7401 double temp;
7402#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007403
7404 CHECK_ERROR;
7405 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7406 XP_ERROR(XPATH_NUMBER_ERROR);
7407 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007408#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007409 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007410 * tmp/temp is a workaround against a gcc compiler bug
7411 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007412 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007413 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007414 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007415 ret = ret * 10;
7416 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007417 ok = 1;
7418 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007419 temp = (double) tmp;
7420 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007421 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007422#else
7423 ret = 0;
7424 while ((CUR >= '0') && (CUR <= '9')) {
7425 ret = ret * 10 + (CUR - '0');
7426 ok = 1;
7427 NEXT;
7428 }
7429#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007430 if (CUR == '.') {
7431 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007432 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7433 XP_ERROR(XPATH_NUMBER_ERROR);
7434 }
7435 while ((CUR >= '0') && (CUR <= '9')) {
7436 mult /= 10;
7437 ret = ret + (CUR - '0') * mult;
7438 NEXT;
7439 }
Owen Taylor3473f882001-02-23 17:55:21 +00007440 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007441 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007442 NEXT;
7443 if (CUR == '-') {
7444 is_exponent_negative = 1;
7445 NEXT;
7446 }
7447 while ((CUR >= '0') && (CUR <= '9')) {
7448 exponent = exponent * 10 + (CUR - '0');
7449 NEXT;
7450 }
7451 if (is_exponent_negative)
7452 exponent = -exponent;
7453 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007454 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007455 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007456 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007457}
7458
7459/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007460 * xmlXPathParseLiteral:
7461 * @ctxt: the XPath Parser context
7462 *
7463 * Parse a Literal
7464 *
7465 * [29] Literal ::= '"' [^"]* '"'
7466 * | "'" [^']* "'"
7467 *
7468 * Returns the value found or NULL in case of error
7469 */
7470static xmlChar *
7471xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7472 const xmlChar *q;
7473 xmlChar *ret = NULL;
7474
7475 if (CUR == '"') {
7476 NEXT;
7477 q = CUR_PTR;
7478 while ((IS_CHAR(CUR)) && (CUR != '"'))
7479 NEXT;
7480 if (!IS_CHAR(CUR)) {
7481 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7482 } else {
7483 ret = xmlStrndup(q, CUR_PTR - q);
7484 NEXT;
7485 }
7486 } else if (CUR == '\'') {
7487 NEXT;
7488 q = CUR_PTR;
7489 while ((IS_CHAR(CUR)) && (CUR != '\''))
7490 NEXT;
7491 if (!IS_CHAR(CUR)) {
7492 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7493 } else {
7494 ret = xmlStrndup(q, CUR_PTR - q);
7495 NEXT;
7496 }
7497 } else {
7498 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7499 }
7500 return(ret);
7501}
7502
7503/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007504 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007505 * @ctxt: the XPath Parser context
7506 *
7507 * Parse a Literal and push it on the stack.
7508 *
7509 * [29] Literal ::= '"' [^"]* '"'
7510 * | "'" [^']* "'"
7511 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007512 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007513 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007514static void
7515xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007516 const xmlChar *q;
7517 xmlChar *ret = NULL;
7518
7519 if (CUR == '"') {
7520 NEXT;
7521 q = CUR_PTR;
7522 while ((IS_CHAR(CUR)) && (CUR != '"'))
7523 NEXT;
7524 if (!IS_CHAR(CUR)) {
7525 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7526 } else {
7527 ret = xmlStrndup(q, CUR_PTR - q);
7528 NEXT;
7529 }
7530 } else if (CUR == '\'') {
7531 NEXT;
7532 q = CUR_PTR;
7533 while ((IS_CHAR(CUR)) && (CUR != '\''))
7534 NEXT;
7535 if (!IS_CHAR(CUR)) {
7536 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7537 } else {
7538 ret = xmlStrndup(q, CUR_PTR - q);
7539 NEXT;
7540 }
7541 } else {
7542 XP_ERROR(XPATH_START_LITERAL_ERROR);
7543 }
7544 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007545 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7546 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007547 xmlFree(ret);
7548}
7549
7550/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007551 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007552 * @ctxt: the XPath Parser context
7553 *
7554 * Parse a VariableReference, evaluate it and push it on the stack.
7555 *
7556 * The variable bindings consist of a mapping from variable names
7557 * to variable values. The value of a variable is an object, which
7558 * of any of the types that are possible for the value of an expression,
7559 * and may also be of additional types not specified here.
7560 *
7561 * Early evaluation is possible since:
7562 * The variable bindings [...] used to evaluate a subexpression are
7563 * always the same as those used to evaluate the containing expression.
7564 *
7565 * [36] VariableReference ::= '$' QName
7566 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007567static void
7568xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007569 xmlChar *name;
7570 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007571
7572 SKIP_BLANKS;
7573 if (CUR != '$') {
7574 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7575 }
7576 NEXT;
7577 name = xmlXPathParseQName(ctxt, &prefix);
7578 if (name == NULL) {
7579 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7580 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007581 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007582 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7583 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007584 SKIP_BLANKS;
7585}
7586
7587/**
7588 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +00007589 * @name: a name string
7590 *
7591 * Is the name given a NodeType one.
7592 *
7593 * [38] NodeType ::= 'comment'
7594 * | 'text'
7595 * | 'processing-instruction'
7596 * | 'node'
7597 *
7598 * Returns 1 if true 0 otherwise
7599 */
7600int
7601xmlXPathIsNodeType(const xmlChar *name) {
7602 if (name == NULL)
7603 return(0);
7604
Daniel Veillard1971ee22002-01-31 20:29:19 +00007605 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007606 return(1);
7607 if (xmlStrEqual(name, BAD_CAST "text"))
7608 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007609 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007610 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007611 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007612 return(1);
7613 return(0);
7614}
7615
7616/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007617 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007618 * @ctxt: the XPath Parser context
7619 *
7620 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7621 * [17] Argument ::= Expr
7622 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007623 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007624 * pushed on the stack
7625 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007626static void
7627xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007628 xmlChar *name;
7629 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007630 int nbargs = 0;
7631
7632 name = xmlXPathParseQName(ctxt, &prefix);
7633 if (name == NULL) {
7634 XP_ERROR(XPATH_EXPR_ERROR);
7635 }
7636 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007637#ifdef DEBUG_EXPR
7638 if (prefix == NULL)
7639 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7640 name);
7641 else
7642 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7643 prefix, name);
7644#endif
7645
Owen Taylor3473f882001-02-23 17:55:21 +00007646 if (CUR != '(') {
7647 XP_ERROR(XPATH_EXPR_ERROR);
7648 }
7649 NEXT;
7650 SKIP_BLANKS;
7651
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007652 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +00007653 if (CUR != ')') {
7654 while (CUR != 0) {
7655 int op1 = ctxt->comp->last;
7656 ctxt->comp->last = -1;
7657 xmlXPathCompileExpr(ctxt);
7658 CHECK_ERROR;
7659 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
7660 nbargs++;
7661 if (CUR == ')') break;
7662 if (CUR != ',') {
7663 XP_ERROR(XPATH_EXPR_ERROR);
7664 }
7665 NEXT;
7666 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007667 }
Owen Taylor3473f882001-02-23 17:55:21 +00007668 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007669 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7670 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007671 NEXT;
7672 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007673}
7674
7675/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007676 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007677 * @ctxt: the XPath Parser context
7678 *
7679 * [15] PrimaryExpr ::= VariableReference
7680 * | '(' Expr ')'
7681 * | Literal
7682 * | Number
7683 * | FunctionCall
7684 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007685 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007686 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007687static void
7688xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007689 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007690 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007691 else if (CUR == '(') {
7692 NEXT;
7693 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007694 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007695 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00007696 if (CUR != ')') {
7697 XP_ERROR(XPATH_EXPR_ERROR);
7698 }
7699 NEXT;
7700 SKIP_BLANKS;
Daniel Veillard01917aa2002-04-10 11:30:41 +00007701 } else if (IS_DIGIT(CUR) || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007702 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007703 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007704 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007705 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007706 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007707 }
7708 SKIP_BLANKS;
7709}
7710
7711/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007712 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007713 * @ctxt: the XPath Parser context
7714 *
7715 * [20] FilterExpr ::= PrimaryExpr
7716 * | FilterExpr Predicate
7717 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007718 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007719 * Square brackets are used to filter expressions in the same way that
7720 * they are used in location paths. It is an error if the expression to
7721 * be filtered does not evaluate to a node-set. The context node list
7722 * used for evaluating the expression in square brackets is the node-set
7723 * to be filtered listed in document order.
7724 */
7725
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007726static void
7727xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
7728 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007729 CHECK_ERROR;
7730 SKIP_BLANKS;
7731
7732 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007733 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00007734 SKIP_BLANKS;
7735 }
7736
7737
7738}
7739
7740/**
7741 * xmlXPathScanName:
7742 * @ctxt: the XPath Parser context
7743 *
7744 * Trickery: parse an XML name but without consuming the input flow
7745 * Needed to avoid insanity in the parser state.
7746 *
7747 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7748 * CombiningChar | Extender
7749 *
7750 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7751 *
7752 * [6] Names ::= Name (S Name)*
7753 *
7754 * Returns the Name parsed or NULL
7755 */
7756
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007757static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007758xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7759 xmlChar buf[XML_MAX_NAMELEN];
7760 int len = 0;
7761
7762 SKIP_BLANKS;
7763 if (!IS_LETTER(CUR) && (CUR != '_') &&
7764 (CUR != ':')) {
7765 return(NULL);
7766 }
7767
7768 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7769 (NXT(len) == '.') || (NXT(len) == '-') ||
7770 (NXT(len) == '_') || (NXT(len) == ':') ||
7771 (IS_COMBINING(NXT(len))) ||
7772 (IS_EXTENDER(NXT(len)))) {
7773 buf[len] = NXT(len);
7774 len++;
7775 if (len >= XML_MAX_NAMELEN) {
7776 xmlGenericError(xmlGenericErrorContext,
7777 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
7778 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7779 (NXT(len) == '.') || (NXT(len) == '-') ||
7780 (NXT(len) == '_') || (NXT(len) == ':') ||
7781 (IS_COMBINING(NXT(len))) ||
7782 (IS_EXTENDER(NXT(len))))
7783 len++;
7784 break;
7785 }
7786 }
7787 return(xmlStrndup(buf, len));
7788}
7789
7790/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007791 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007792 * @ctxt: the XPath Parser context
7793 *
7794 * [19] PathExpr ::= LocationPath
7795 * | FilterExpr
7796 * | FilterExpr '/' RelativeLocationPath
7797 * | FilterExpr '//' RelativeLocationPath
7798 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007799 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007800 * The / operator and // operators combine an arbitrary expression
7801 * and a relative location path. It is an error if the expression
7802 * does not evaluate to a node-set.
7803 * The / operator does composition in the same way as when / is
7804 * used in a location path. As in location paths, // is short for
7805 * /descendant-or-self::node()/.
7806 */
7807
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007808static void
7809xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007810 int lc = 1; /* Should we branch to LocationPath ? */
7811 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7812
7813 SKIP_BLANKS;
7814 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
Daniel Veillard01917aa2002-04-10 11:30:41 +00007815 (CUR == '\'') || (CUR == '"') || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00007816 lc = 0;
7817 } else if (CUR == '*') {
7818 /* relative or absolute location path */
7819 lc = 1;
7820 } else if (CUR == '/') {
7821 /* relative or absolute location path */
7822 lc = 1;
7823 } else if (CUR == '@') {
7824 /* relative abbreviated attribute location path */
7825 lc = 1;
7826 } else if (CUR == '.') {
7827 /* relative abbreviated attribute location path */
7828 lc = 1;
7829 } else {
7830 /*
7831 * Problem is finding if we have a name here whether it's:
7832 * - a nodetype
7833 * - a function call in which case it's followed by '('
7834 * - an axis in which case it's followed by ':'
7835 * - a element name
7836 * We do an a priori analysis here rather than having to
7837 * maintain parsed token content through the recursive function
7838 * calls. This looks uglier but makes the code quite easier to
7839 * read/write/debug.
7840 */
7841 SKIP_BLANKS;
7842 name = xmlXPathScanName(ctxt);
7843 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7844#ifdef DEBUG_STEP
7845 xmlGenericError(xmlGenericErrorContext,
7846 "PathExpr: Axis\n");
7847#endif
7848 lc = 1;
7849 xmlFree(name);
7850 } else if (name != NULL) {
7851 int len =xmlStrlen(name);
7852 int blank = 0;
7853
7854
7855 while (NXT(len) != 0) {
7856 if (NXT(len) == '/') {
7857 /* element name */
7858#ifdef DEBUG_STEP
7859 xmlGenericError(xmlGenericErrorContext,
7860 "PathExpr: AbbrRelLocation\n");
7861#endif
7862 lc = 1;
7863 break;
7864 } else if (IS_BLANK(NXT(len))) {
7865 /* skip to next */
7866 blank = 1;
7867 } else if (NXT(len) == ':') {
7868#ifdef DEBUG_STEP
7869 xmlGenericError(xmlGenericErrorContext,
7870 "PathExpr: AbbrRelLocation\n");
7871#endif
7872 lc = 1;
7873 break;
7874 } else if ((NXT(len) == '(')) {
7875 /* Note Type or Function */
7876 if (xmlXPathIsNodeType(name)) {
7877#ifdef DEBUG_STEP
7878 xmlGenericError(xmlGenericErrorContext,
7879 "PathExpr: Type search\n");
7880#endif
7881 lc = 1;
7882 } else {
7883#ifdef DEBUG_STEP
7884 xmlGenericError(xmlGenericErrorContext,
7885 "PathExpr: function call\n");
7886#endif
7887 lc = 0;
7888 }
7889 break;
7890 } else if ((NXT(len) == '[')) {
7891 /* element name */
7892#ifdef DEBUG_STEP
7893 xmlGenericError(xmlGenericErrorContext,
7894 "PathExpr: AbbrRelLocation\n");
7895#endif
7896 lc = 1;
7897 break;
7898 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
7899 (NXT(len) == '=')) {
7900 lc = 1;
7901 break;
7902 } else {
7903 lc = 1;
7904 break;
7905 }
7906 len++;
7907 }
7908 if (NXT(len) == 0) {
7909#ifdef DEBUG_STEP
7910 xmlGenericError(xmlGenericErrorContext,
7911 "PathExpr: AbbrRelLocation\n");
7912#endif
7913 /* element name */
7914 lc = 1;
7915 }
7916 xmlFree(name);
7917 } else {
7918 /* make sure all cases are covered explicitely */
7919 XP_ERROR(XPATH_EXPR_ERROR);
7920 }
7921 }
7922
7923 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007924 if (CUR == '/') {
7925 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
7926 } else {
7927 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007928 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007929 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007930 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007931 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007932 CHECK_ERROR;
7933 if ((CUR == '/') && (NXT(1) == '/')) {
7934 SKIP(2);
7935 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007936
7937 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7938 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
7939 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
7940
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007941 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007942 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007943 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007944 }
7945 }
7946 SKIP_BLANKS;
7947}
7948
7949/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007950 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007951 * @ctxt: the XPath Parser context
7952 *
7953 * [18] UnionExpr ::= PathExpr
7954 * | UnionExpr '|' PathExpr
7955 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007956 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007957 */
7958
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007959static void
7960xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
7961 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007962 CHECK_ERROR;
7963 SKIP_BLANKS;
7964 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007965 int op1 = ctxt->comp->last;
7966 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007967
7968 NEXT;
7969 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007970 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007971
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007972 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
7973
Owen Taylor3473f882001-02-23 17:55:21 +00007974 SKIP_BLANKS;
7975 }
Owen Taylor3473f882001-02-23 17:55:21 +00007976}
7977
7978/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007979 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007980 * @ctxt: the XPath Parser context
7981 *
7982 * [27] UnaryExpr ::= UnionExpr
7983 * | '-' UnaryExpr
7984 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007985 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007986 */
7987
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007988static void
7989xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007990 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007991 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007992
7993 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00007994 while (CUR == '-') {
7995 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007996 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007997 NEXT;
7998 SKIP_BLANKS;
7999 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008000
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008001 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008002 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008003 if (found) {
8004 if (minus)
8005 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8006 else
8007 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008008 }
8009}
8010
8011/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008012 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008013 * @ctxt: the XPath Parser context
8014 *
8015 * [26] MultiplicativeExpr ::= UnaryExpr
8016 * | MultiplicativeExpr MultiplyOperator UnaryExpr
8017 * | MultiplicativeExpr 'div' UnaryExpr
8018 * | MultiplicativeExpr 'mod' UnaryExpr
8019 * [34] MultiplyOperator ::= '*'
8020 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008021 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008022 */
8023
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008024static void
8025xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8026 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008027 CHECK_ERROR;
8028 SKIP_BLANKS;
8029 while ((CUR == '*') ||
8030 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8031 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8032 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008033 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008034
8035 if (CUR == '*') {
8036 op = 0;
8037 NEXT;
8038 } else if (CUR == 'd') {
8039 op = 1;
8040 SKIP(3);
8041 } else if (CUR == 'm') {
8042 op = 2;
8043 SKIP(3);
8044 }
8045 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008046 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008047 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008048 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008049 SKIP_BLANKS;
8050 }
8051}
8052
8053/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008054 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008055 * @ctxt: the XPath Parser context
8056 *
8057 * [25] AdditiveExpr ::= MultiplicativeExpr
8058 * | AdditiveExpr '+' MultiplicativeExpr
8059 * | AdditiveExpr '-' MultiplicativeExpr
8060 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008061 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008062 */
8063
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008064static void
8065xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008066
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008067 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008068 CHECK_ERROR;
8069 SKIP_BLANKS;
8070 while ((CUR == '+') || (CUR == '-')) {
8071 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008072 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008073
8074 if (CUR == '+') plus = 1;
8075 else plus = 0;
8076 NEXT;
8077 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008078 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008079 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008080 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008081 SKIP_BLANKS;
8082 }
8083}
8084
8085/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008086 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008087 * @ctxt: the XPath Parser context
8088 *
8089 * [24] RelationalExpr ::= AdditiveExpr
8090 * | RelationalExpr '<' AdditiveExpr
8091 * | RelationalExpr '>' AdditiveExpr
8092 * | RelationalExpr '<=' AdditiveExpr
8093 * | RelationalExpr '>=' AdditiveExpr
8094 *
8095 * A <= B > C is allowed ? Answer from James, yes with
8096 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8097 * which is basically what got implemented.
8098 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008099 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00008100 * on the stack
8101 */
8102
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008103static void
8104xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8105 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008106 CHECK_ERROR;
8107 SKIP_BLANKS;
8108 while ((CUR == '<') ||
8109 (CUR == '>') ||
8110 ((CUR == '<') && (NXT(1) == '=')) ||
8111 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008112 int inf, strict;
8113 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008114
8115 if (CUR == '<') inf = 1;
8116 else inf = 0;
8117 if (NXT(1) == '=') strict = 0;
8118 else strict = 1;
8119 NEXT;
8120 if (!strict) NEXT;
8121 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008122 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008123 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008124 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00008125 SKIP_BLANKS;
8126 }
8127}
8128
8129/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008130 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008131 * @ctxt: the XPath Parser context
8132 *
8133 * [23] EqualityExpr ::= RelationalExpr
8134 * | EqualityExpr '=' RelationalExpr
8135 * | EqualityExpr '!=' RelationalExpr
8136 *
8137 * A != B != C is allowed ? Answer from James, yes with
8138 * (RelationalExpr = RelationalExpr) = RelationalExpr
8139 * (RelationalExpr != RelationalExpr) != RelationalExpr
8140 * which is basically what got implemented.
8141 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008142 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008143 *
8144 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008145static void
8146xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8147 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008148 CHECK_ERROR;
8149 SKIP_BLANKS;
8150 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008151 int eq;
8152 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008153
8154 if (CUR == '=') eq = 1;
8155 else eq = 0;
8156 NEXT;
8157 if (!eq) NEXT;
8158 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008159 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008160 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008161 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008162 SKIP_BLANKS;
8163 }
8164}
8165
8166/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008167 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008168 * @ctxt: the XPath Parser context
8169 *
8170 * [22] AndExpr ::= EqualityExpr
8171 * | AndExpr 'and' EqualityExpr
8172 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008173 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008174 *
8175 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008176static void
8177xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8178 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008179 CHECK_ERROR;
8180 SKIP_BLANKS;
8181 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008182 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008183 SKIP(3);
8184 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008185 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008186 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008187 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008188 SKIP_BLANKS;
8189 }
8190}
8191
8192/**
Daniel Veillard591b4be2003-02-09 23:33:36 +00008193 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008194 * @ctxt: the XPath Parser context
8195 *
8196 * [14] Expr ::= OrExpr
8197 * [21] OrExpr ::= AndExpr
8198 * | OrExpr 'or' AndExpr
8199 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008200 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00008201 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008202static void
8203xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8204 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008205 CHECK_ERROR;
8206 SKIP_BLANKS;
8207 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008208 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008209 SKIP(2);
8210 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008211 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008212 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008213 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8214 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00008215 SKIP_BLANKS;
8216 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008217 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8218 /* more ops could be optimized too */
8219 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8220 }
Owen Taylor3473f882001-02-23 17:55:21 +00008221}
8222
8223/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008224 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00008225 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008226 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00008227 *
8228 * [8] Predicate ::= '[' PredicateExpr ']'
8229 * [9] PredicateExpr ::= Expr
8230 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008231 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008232 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008233static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008234xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008235 int op1 = ctxt->comp->last;
8236
8237 SKIP_BLANKS;
8238 if (CUR != '[') {
8239 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8240 }
8241 NEXT;
8242 SKIP_BLANKS;
8243
8244 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008245 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008246 CHECK_ERROR;
8247
8248 if (CUR != ']') {
8249 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8250 }
8251
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008252 if (filter)
8253 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8254 else
8255 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008256
8257 NEXT;
8258 SKIP_BLANKS;
8259}
8260
8261/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008262 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00008263 * @ctxt: the XPath Parser context
8264 * @test: pointer to a xmlXPathTestVal
8265 * @type: pointer to a xmlXPathTypeVal
8266 * @prefix: placeholder for a possible name prefix
8267 *
8268 * [7] NodeTest ::= NameTest
8269 * | NodeType '(' ')'
8270 * | 'processing-instruction' '(' Literal ')'
8271 *
8272 * [37] NameTest ::= '*'
8273 * | NCName ':' '*'
8274 * | QName
8275 * [38] NodeType ::= 'comment'
8276 * | 'text'
8277 * | 'processing-instruction'
8278 * | 'node'
8279 *
8280 * Returns the name found and update @test, @type and @prefix appropriately
8281 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008282static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008283xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8284 xmlXPathTypeVal *type, const xmlChar **prefix,
8285 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008286 int blanks;
8287
8288 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8289 STRANGE;
8290 return(NULL);
8291 }
8292 *type = 0;
8293 *test = 0;
8294 *prefix = NULL;
8295 SKIP_BLANKS;
8296
8297 if ((name == NULL) && (CUR == '*')) {
8298 /*
8299 * All elements
8300 */
8301 NEXT;
8302 *test = NODE_TEST_ALL;
8303 return(NULL);
8304 }
8305
8306 if (name == NULL)
8307 name = xmlXPathParseNCName(ctxt);
8308 if (name == NULL) {
8309 XP_ERROR0(XPATH_EXPR_ERROR);
8310 }
8311
8312 blanks = IS_BLANK(CUR);
8313 SKIP_BLANKS;
8314 if (CUR == '(') {
8315 NEXT;
8316 /*
8317 * NodeType or PI search
8318 */
8319 if (xmlStrEqual(name, BAD_CAST "comment"))
8320 *type = NODE_TYPE_COMMENT;
8321 else if (xmlStrEqual(name, BAD_CAST "node"))
8322 *type = NODE_TYPE_NODE;
8323 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8324 *type = NODE_TYPE_PI;
8325 else if (xmlStrEqual(name, BAD_CAST "text"))
8326 *type = NODE_TYPE_TEXT;
8327 else {
8328 if (name != NULL)
8329 xmlFree(name);
8330 XP_ERROR0(XPATH_EXPR_ERROR);
8331 }
8332
8333 *test = NODE_TEST_TYPE;
8334
8335 SKIP_BLANKS;
8336 if (*type == NODE_TYPE_PI) {
8337 /*
8338 * Specific case: search a PI by name.
8339 */
Owen Taylor3473f882001-02-23 17:55:21 +00008340 if (name != NULL)
8341 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008342 name = NULL;
8343 if (CUR != ')') {
8344 name = xmlXPathParseLiteral(ctxt);
8345 CHECK_ERROR 0;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00008346 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00008347 SKIP_BLANKS;
8348 }
Owen Taylor3473f882001-02-23 17:55:21 +00008349 }
8350 if (CUR != ')') {
8351 if (name != NULL)
8352 xmlFree(name);
8353 XP_ERROR0(XPATH_UNCLOSED_ERROR);
8354 }
8355 NEXT;
8356 return(name);
8357 }
8358 *test = NODE_TEST_NAME;
8359 if ((!blanks) && (CUR == ':')) {
8360 NEXT;
8361
8362 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008363 * Since currently the parser context don't have a
8364 * namespace list associated:
8365 * The namespace name for this prefix can be computed
8366 * only at evaluation time. The compilation is done
8367 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008368 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008369#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008370 *prefix = xmlXPathNsLookup(ctxt->context, name);
8371 if (name != NULL)
8372 xmlFree(name);
8373 if (*prefix == NULL) {
8374 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8375 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008376#else
8377 *prefix = name;
8378#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008379
8380 if (CUR == '*') {
8381 /*
8382 * All elements
8383 */
8384 NEXT;
8385 *test = NODE_TEST_ALL;
8386 return(NULL);
8387 }
8388
8389 name = xmlXPathParseNCName(ctxt);
8390 if (name == NULL) {
8391 XP_ERROR0(XPATH_EXPR_ERROR);
8392 }
8393 }
8394 return(name);
8395}
8396
8397/**
8398 * xmlXPathIsAxisName:
8399 * @name: a preparsed name token
8400 *
8401 * [6] AxisName ::= 'ancestor'
8402 * | 'ancestor-or-self'
8403 * | 'attribute'
8404 * | 'child'
8405 * | 'descendant'
8406 * | 'descendant-or-self'
8407 * | 'following'
8408 * | 'following-sibling'
8409 * | 'namespace'
8410 * | 'parent'
8411 * | 'preceding'
8412 * | 'preceding-sibling'
8413 * | 'self'
8414 *
8415 * Returns the axis or 0
8416 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008417static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008418xmlXPathIsAxisName(const xmlChar *name) {
8419 xmlXPathAxisVal ret = 0;
8420 switch (name[0]) {
8421 case 'a':
8422 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8423 ret = AXIS_ANCESTOR;
8424 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8425 ret = AXIS_ANCESTOR_OR_SELF;
8426 if (xmlStrEqual(name, BAD_CAST "attribute"))
8427 ret = AXIS_ATTRIBUTE;
8428 break;
8429 case 'c':
8430 if (xmlStrEqual(name, BAD_CAST "child"))
8431 ret = AXIS_CHILD;
8432 break;
8433 case 'd':
8434 if (xmlStrEqual(name, BAD_CAST "descendant"))
8435 ret = AXIS_DESCENDANT;
8436 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8437 ret = AXIS_DESCENDANT_OR_SELF;
8438 break;
8439 case 'f':
8440 if (xmlStrEqual(name, BAD_CAST "following"))
8441 ret = AXIS_FOLLOWING;
8442 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8443 ret = AXIS_FOLLOWING_SIBLING;
8444 break;
8445 case 'n':
8446 if (xmlStrEqual(name, BAD_CAST "namespace"))
8447 ret = AXIS_NAMESPACE;
8448 break;
8449 case 'p':
8450 if (xmlStrEqual(name, BAD_CAST "parent"))
8451 ret = AXIS_PARENT;
8452 if (xmlStrEqual(name, BAD_CAST "preceding"))
8453 ret = AXIS_PRECEDING;
8454 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8455 ret = AXIS_PRECEDING_SIBLING;
8456 break;
8457 case 's':
8458 if (xmlStrEqual(name, BAD_CAST "self"))
8459 ret = AXIS_SELF;
8460 break;
8461 }
8462 return(ret);
8463}
8464
8465/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008466 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008467 * @ctxt: the XPath Parser context
8468 *
8469 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8470 * | AbbreviatedStep
8471 *
8472 * [12] AbbreviatedStep ::= '.' | '..'
8473 *
8474 * [5] AxisSpecifier ::= AxisName '::'
8475 * | AbbreviatedAxisSpecifier
8476 *
8477 * [13] AbbreviatedAxisSpecifier ::= '@'?
8478 *
8479 * Modified for XPtr range support as:
8480 *
8481 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8482 * | AbbreviatedStep
8483 * | 'range-to' '(' Expr ')' Predicate*
8484 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008485 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008486 * A location step of . is short for self::node(). This is
8487 * particularly useful in conjunction with //. For example, the
8488 * location path .//para is short for
8489 * self::node()/descendant-or-self::node()/child::para
8490 * and so will select all para descendant elements of the context
8491 * node.
8492 * Similarly, a location step of .. is short for parent::node().
8493 * For example, ../title is short for parent::node()/child::title
8494 * and so will select the title children of the parent of the context
8495 * node.
8496 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008497static void
8498xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008499#ifdef LIBXML_XPTR_ENABLED
8500 int rangeto = 0;
8501 int op2 = -1;
8502#endif
8503
Owen Taylor3473f882001-02-23 17:55:21 +00008504 SKIP_BLANKS;
8505 if ((CUR == '.') && (NXT(1) == '.')) {
8506 SKIP(2);
8507 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008508 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8509 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008510 } else if (CUR == '.') {
8511 NEXT;
8512 SKIP_BLANKS;
8513 } else {
8514 xmlChar *name = NULL;
8515 const xmlChar *prefix = NULL;
8516 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008517 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008518 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008519 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008520
8521 /*
8522 * The modification needed for XPointer change to the production
8523 */
8524#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008525 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008526 name = xmlXPathParseNCName(ctxt);
8527 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008528 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008529 xmlFree(name);
8530 SKIP_BLANKS;
8531 if (CUR != '(') {
8532 XP_ERROR(XPATH_EXPR_ERROR);
8533 }
8534 NEXT;
8535 SKIP_BLANKS;
8536
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008537 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008538 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008539 CHECK_ERROR;
8540
8541 SKIP_BLANKS;
8542 if (CUR != ')') {
8543 XP_ERROR(XPATH_EXPR_ERROR);
8544 }
8545 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008546 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008547 goto eval_predicates;
8548 }
8549 }
8550#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008551 if (CUR == '*') {
8552 axis = AXIS_CHILD;
8553 } else {
8554 if (name == NULL)
8555 name = xmlXPathParseNCName(ctxt);
8556 if (name != NULL) {
8557 axis = xmlXPathIsAxisName(name);
8558 if (axis != 0) {
8559 SKIP_BLANKS;
8560 if ((CUR == ':') && (NXT(1) == ':')) {
8561 SKIP(2);
8562 xmlFree(name);
8563 name = NULL;
8564 } else {
8565 /* an element name can conflict with an axis one :-\ */
8566 axis = AXIS_CHILD;
8567 }
Owen Taylor3473f882001-02-23 17:55:21 +00008568 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008569 axis = AXIS_CHILD;
8570 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008571 } else if (CUR == '@') {
8572 NEXT;
8573 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008574 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008575 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008576 }
Owen Taylor3473f882001-02-23 17:55:21 +00008577 }
8578
8579 CHECK_ERROR;
8580
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008581 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008582 if (test == 0)
8583 return;
8584
8585#ifdef DEBUG_STEP
8586 xmlGenericError(xmlGenericErrorContext,
8587 "Basis : computing new set\n");
8588#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008589
Owen Taylor3473f882001-02-23 17:55:21 +00008590#ifdef DEBUG_STEP
8591 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008592 if (ctxt->value == NULL)
8593 xmlGenericError(xmlGenericErrorContext, "no value\n");
8594 else if (ctxt->value->nodesetval == NULL)
8595 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8596 else
8597 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008598#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008599
8600eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008601 op1 = ctxt->comp->last;
8602 ctxt->comp->last = -1;
8603
Owen Taylor3473f882001-02-23 17:55:21 +00008604 SKIP_BLANKS;
8605 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008606 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008607 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008608
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008609#ifdef LIBXML_XPTR_ENABLED
8610 if (rangeto) {
8611 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8612 } else
8613#endif
8614 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8615 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008616
Owen Taylor3473f882001-02-23 17:55:21 +00008617 }
8618#ifdef DEBUG_STEP
8619 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008620 if (ctxt->value == NULL)
8621 xmlGenericError(xmlGenericErrorContext, "no value\n");
8622 else if (ctxt->value->nodesetval == NULL)
8623 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8624 else
8625 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8626 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008627#endif
8628}
8629
8630/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008631 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008632 * @ctxt: the XPath Parser context
8633 *
8634 * [3] RelativeLocationPath ::= Step
8635 * | RelativeLocationPath '/' Step
8636 * | AbbreviatedRelativeLocationPath
8637 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8638 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008639 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008640 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008641static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008642xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008643(xmlXPathParserContextPtr ctxt) {
8644 SKIP_BLANKS;
8645 if ((CUR == '/') && (NXT(1) == '/')) {
8646 SKIP(2);
8647 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008648 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8649 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008650 } else if (CUR == '/') {
8651 NEXT;
8652 SKIP_BLANKS;
8653 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008654 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008655 SKIP_BLANKS;
8656 while (CUR == '/') {
8657 if ((CUR == '/') && (NXT(1) == '/')) {
8658 SKIP(2);
8659 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008660 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008661 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008662 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008663 } else if (CUR == '/') {
8664 NEXT;
8665 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008666 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008667 }
8668 SKIP_BLANKS;
8669 }
8670}
8671
8672/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008673 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008674 * @ctxt: the XPath Parser context
8675 *
8676 * [1] LocationPath ::= RelativeLocationPath
8677 * | AbsoluteLocationPath
8678 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8679 * | AbbreviatedAbsoluteLocationPath
8680 * [10] AbbreviatedAbsoluteLocationPath ::=
8681 * '//' RelativeLocationPath
8682 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008683 * Compile a location path
8684 *
Owen Taylor3473f882001-02-23 17:55:21 +00008685 * // is short for /descendant-or-self::node()/. For example,
8686 * //para is short for /descendant-or-self::node()/child::para and
8687 * so will select any para element in the document (even a para element
8688 * that is a document element will be selected by //para since the
8689 * document element node is a child of the root node); div//para is
8690 * short for div/descendant-or-self::node()/child::para and so will
8691 * select all para descendants of div children.
8692 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008693static void
8694xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008695 SKIP_BLANKS;
8696 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008697 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008698 } else {
8699 while (CUR == '/') {
8700 if ((CUR == '/') && (NXT(1) == '/')) {
8701 SKIP(2);
8702 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008703 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8704 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008705 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008706 } else if (CUR == '/') {
8707 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008708 SKIP_BLANKS;
8709 if ((CUR != 0 ) &&
8710 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
8711 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008712 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008713 }
8714 }
8715 }
8716}
8717
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008718/************************************************************************
8719 * *
8720 * XPath precompiled expression evaluation *
8721 * *
8722 ************************************************************************/
8723
Daniel Veillardf06307e2001-07-03 10:35:50 +00008724static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008725xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8726
8727/**
8728 * xmlXPathNodeCollectAndTest:
8729 * @ctxt: the XPath Parser context
8730 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008731 * @first: pointer to the first element in document order
8732 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008733 *
8734 * This is the function implementing a step: based on the current list
8735 * of nodes, it builds up a new list, looking at all nodes under that
8736 * axis and selecting them it also do the predicate filtering
8737 *
8738 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00008739 *
8740 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008741 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008742static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008743xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008744 xmlXPathStepOpPtr op,
8745 xmlNodePtr * first, xmlNodePtr * last)
8746{
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008747 xmlXPathAxisVal axis = op->value;
8748 xmlXPathTestVal test = op->value2;
8749 xmlXPathTypeVal type = op->value3;
8750 const xmlChar *prefix = op->value4;
8751 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008752 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008753
8754#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008755 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008756#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008757 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008758 xmlNodeSetPtr ret, list;
8759 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008760 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00008761 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008762 xmlNodePtr cur = NULL;
8763 xmlXPathObjectPtr obj;
8764 xmlNodeSetPtr nodelist;
8765 xmlNodePtr tmp;
8766
Daniel Veillardf06307e2001-07-03 10:35:50 +00008767 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008768 obj = valuePop(ctxt);
8769 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00008770 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008771 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008772 URI = xmlXPathNsLookup(ctxt->context, prefix);
8773 if (URI == NULL)
8774 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008775 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008776#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008777 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008778#endif
8779 switch (axis) {
8780 case AXIS_ANCESTOR:
8781#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008782 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008783#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008784 first = NULL;
8785 next = xmlXPathNextAncestor;
8786 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008787 case AXIS_ANCESTOR_OR_SELF:
8788#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008789 xmlGenericError(xmlGenericErrorContext,
8790 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008791#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008792 first = NULL;
8793 next = xmlXPathNextAncestorOrSelf;
8794 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008795 case AXIS_ATTRIBUTE:
8796#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008797 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008798#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008799 first = NULL;
8800 last = NULL;
8801 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00008802 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008803 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008804 case AXIS_CHILD:
8805#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008806 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008807#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008808 last = NULL;
8809 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00008810 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008811 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008812 case AXIS_DESCENDANT:
8813#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008814 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008815#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008816 last = NULL;
8817 next = xmlXPathNextDescendant;
8818 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008819 case AXIS_DESCENDANT_OR_SELF:
8820#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008821 xmlGenericError(xmlGenericErrorContext,
8822 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008823#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008824 last = NULL;
8825 next = xmlXPathNextDescendantOrSelf;
8826 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008827 case AXIS_FOLLOWING:
8828#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008829 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008830#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008831 last = NULL;
8832 next = xmlXPathNextFollowing;
8833 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008834 case AXIS_FOLLOWING_SIBLING:
8835#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008836 xmlGenericError(xmlGenericErrorContext,
8837 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008838#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008839 last = NULL;
8840 next = xmlXPathNextFollowingSibling;
8841 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008842 case AXIS_NAMESPACE:
8843#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008844 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008845#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008846 first = NULL;
8847 last = NULL;
8848 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00008849 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008850 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008851 case AXIS_PARENT:
8852#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008853 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008854#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008855 first = NULL;
8856 next = xmlXPathNextParent;
8857 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008858 case AXIS_PRECEDING:
8859#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008860 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008861#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008862 first = NULL;
8863 next = xmlXPathNextPrecedingInternal;
8864 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008865 case AXIS_PRECEDING_SIBLING:
8866#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008867 xmlGenericError(xmlGenericErrorContext,
8868 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008869#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008870 first = NULL;
8871 next = xmlXPathNextPrecedingSibling;
8872 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008873 case AXIS_SELF:
8874#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008875 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008876#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008877 first = NULL;
8878 last = NULL;
8879 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00008880 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008881 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008882 }
8883 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008884 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008885
8886 nodelist = obj->nodesetval;
8887 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008888 xmlXPathFreeObject(obj);
8889 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8890 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008891 }
8892 addNode = xmlXPathNodeSetAddUnique;
8893 ret = NULL;
8894#ifdef DEBUG_STEP
8895 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008896 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008897 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008898 case NODE_TEST_NONE:
8899 xmlGenericError(xmlGenericErrorContext,
8900 " searching for none !!!\n");
8901 break;
8902 case NODE_TEST_TYPE:
8903 xmlGenericError(xmlGenericErrorContext,
8904 " searching for type %d\n", type);
8905 break;
8906 case NODE_TEST_PI:
8907 xmlGenericError(xmlGenericErrorContext,
8908 " searching for PI !!!\n");
8909 break;
8910 case NODE_TEST_ALL:
8911 xmlGenericError(xmlGenericErrorContext,
8912 " searching for *\n");
8913 break;
8914 case NODE_TEST_NS:
8915 xmlGenericError(xmlGenericErrorContext,
8916 " searching for namespace %s\n",
8917 prefix);
8918 break;
8919 case NODE_TEST_NAME:
8920 xmlGenericError(xmlGenericErrorContext,
8921 " searching for name %s\n", name);
8922 if (prefix != NULL)
8923 xmlGenericError(xmlGenericErrorContext,
8924 " with namespace %s\n", prefix);
8925 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008926 }
8927 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8928#endif
8929 /*
8930 * 2.3 Node Tests
8931 * - For the attribute axis, the principal node type is attribute.
8932 * - For the namespace axis, the principal node type is namespace.
8933 * - For other axes, the principal node type is element.
8934 *
8935 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008936 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008937 * select all element children of the context node
8938 */
8939 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008940 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008941 ctxt->context->node = nodelist->nodeTab[i];
8942
Daniel Veillardf06307e2001-07-03 10:35:50 +00008943 cur = NULL;
8944 list = xmlXPathNodeSetCreate(NULL);
8945 do {
8946 cur = next(ctxt, cur);
8947 if (cur == NULL)
8948 break;
8949 if ((first != NULL) && (*first == cur))
8950 break;
8951 if (((t % 256) == 0) &&
8952 (first != NULL) && (*first != NULL) &&
8953 (xmlXPathCmpNodes(*first, cur) >= 0))
8954 break;
8955 if ((last != NULL) && (*last == cur))
8956 break;
8957 if (((t % 256) == 0) &&
8958 (last != NULL) && (*last != NULL) &&
8959 (xmlXPathCmpNodes(cur, *last) >= 0))
8960 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008961 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008962#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008963 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
8964#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008965 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008966 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008967 ctxt->context->node = tmp;
8968 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008969 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008970 if ((cur->type == type) ||
8971 ((type == NODE_TYPE_NODE) &&
8972 ((cur->type == XML_DOCUMENT_NODE) ||
8973 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8974 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00008975 (cur->type == XML_NAMESPACE_DECL) ||
8976 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00008977 (cur->type == XML_PI_NODE) ||
8978 (cur->type == XML_COMMENT_NODE) ||
8979 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00008980 (cur->type == XML_TEXT_NODE))) ||
8981 ((type == NODE_TYPE_TEXT) &&
8982 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008983#ifdef DEBUG_STEP
8984 n++;
8985#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008986 addNode(list, cur);
8987 }
8988 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008989 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008990 if (cur->type == XML_PI_NODE) {
8991 if ((name != NULL) &&
8992 (!xmlStrEqual(name, cur->name)))
8993 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008994#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008995 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008996#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008997 addNode(list, cur);
8998 }
8999 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009000 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009001 if (axis == AXIS_ATTRIBUTE) {
9002 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009003#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009004 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009005#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009006 addNode(list, cur);
9007 }
9008 } else if (axis == AXIS_NAMESPACE) {
9009 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009010#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009011 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009012#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009013 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9014 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009015 }
9016 } else {
9017 if (cur->type == XML_ELEMENT_NODE) {
9018 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009019#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009020 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009021#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009022 addNode(list, cur);
9023 } else if ((cur->ns != NULL) &&
9024 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009025#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009026 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009027#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009028 addNode(list, cur);
9029 }
9030 }
9031 }
9032 break;
9033 case NODE_TEST_NS:{
9034 TODO;
9035 break;
9036 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009037 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009038 switch (cur->type) {
9039 case XML_ELEMENT_NODE:
9040 if (xmlStrEqual(name, cur->name)) {
9041 if (prefix == NULL) {
9042 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009043#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009044 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009045#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009046 addNode(list, cur);
9047 }
9048 } else {
9049 if ((cur->ns != NULL) &&
9050 (xmlStrEqual(URI,
9051 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009052#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009053 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009054#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009055 addNode(list, cur);
9056 }
9057 }
9058 }
9059 break;
9060 case XML_ATTRIBUTE_NODE:{
9061 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009062
Daniel Veillardf06307e2001-07-03 10:35:50 +00009063 if (xmlStrEqual(name, attr->name)) {
9064 if (prefix == NULL) {
9065 if ((attr->ns == NULL) ||
9066 (attr->ns->prefix == NULL)) {
9067#ifdef DEBUG_STEP
9068 n++;
9069#endif
9070 addNode(list,
9071 (xmlNodePtr) attr);
9072 }
9073 } else {
9074 if ((attr->ns != NULL) &&
9075 (xmlStrEqual(URI,
9076 attr->ns->
9077 href))) {
9078#ifdef DEBUG_STEP
9079 n++;
9080#endif
9081 addNode(list,
9082 (xmlNodePtr) attr);
9083 }
9084 }
9085 }
9086 break;
9087 }
9088 case XML_NAMESPACE_DECL:
9089 if (cur->type == XML_NAMESPACE_DECL) {
9090 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009091
Daniel Veillardf06307e2001-07-03 10:35:50 +00009092 if ((ns->prefix != NULL) && (name != NULL)
9093 && (xmlStrEqual(ns->prefix, name))) {
9094#ifdef DEBUG_STEP
9095 n++;
9096#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009097 xmlXPathNodeSetAddNs(list,
9098 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009099 }
9100 }
9101 break;
9102 default:
9103 break;
9104 }
9105 break;
9106 break;
9107 }
9108 } while (cur != NULL);
9109
9110 /*
9111 * If there is some predicate filtering do it now
9112 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009113 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009114 xmlXPathObjectPtr obj2;
9115
9116 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9117 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9118 CHECK_TYPE0(XPATH_NODESET);
9119 obj2 = valuePop(ctxt);
9120 list = obj2->nodesetval;
9121 obj2->nodesetval = NULL;
9122 xmlXPathFreeObject(obj2);
9123 }
9124 if (ret == NULL) {
9125 ret = list;
9126 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009127 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009128 xmlXPathFreeNodeSet(list);
9129 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009130 }
9131 ctxt->context->node = tmp;
9132#ifdef DEBUG_STEP
9133 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009134 "\nExamined %d nodes, found %d nodes at that step\n",
9135 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009136#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009137 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009138 if ((obj->boolval) && (obj->user != NULL)) {
9139 ctxt->value->boolval = 1;
9140 ctxt->value->user = obj->user;
9141 obj->user = NULL;
9142 obj->boolval = 0;
9143 }
9144 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009145 return(t);
9146}
9147
9148/**
9149 * xmlXPathNodeCollectAndTestNth:
9150 * @ctxt: the XPath Parser context
9151 * @op: the XPath precompiled step operation
9152 * @indx: the index to collect
9153 * @first: pointer to the first element in document order
9154 * @last: pointer to the last element in document order
9155 *
9156 * This is the function implementing a step: based on the current list
9157 * of nodes, it builds up a new list, looking at all nodes under that
9158 * axis and selecting them it also do the predicate filtering
9159 *
9160 * Pushes the new NodeSet resulting from the search.
9161 * Returns the number of node traversed
9162 */
9163static int
9164xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9165 xmlXPathStepOpPtr op, int indx,
9166 xmlNodePtr * first, xmlNodePtr * last)
9167{
9168 xmlXPathAxisVal axis = op->value;
9169 xmlXPathTestVal test = op->value2;
9170 xmlXPathTypeVal type = op->value3;
9171 const xmlChar *prefix = op->value4;
9172 const xmlChar *name = op->value5;
9173 const xmlChar *URI = NULL;
9174 int n = 0, t = 0;
9175
9176 int i;
9177 xmlNodeSetPtr list;
9178 xmlXPathTraversalFunction next = NULL;
9179 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9180 xmlNodePtr cur = NULL;
9181 xmlXPathObjectPtr obj;
9182 xmlNodeSetPtr nodelist;
9183 xmlNodePtr tmp;
9184
9185 CHECK_TYPE0(XPATH_NODESET);
9186 obj = valuePop(ctxt);
9187 addNode = xmlXPathNodeSetAdd;
9188 if (prefix != NULL) {
9189 URI = xmlXPathNsLookup(ctxt->context, prefix);
9190 if (URI == NULL)
9191 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9192 }
9193#ifdef DEBUG_STEP_NTH
9194 xmlGenericError(xmlGenericErrorContext, "new step : ");
9195 if (first != NULL) {
9196 if (*first != NULL)
9197 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9198 (*first)->name);
9199 else
9200 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9201 }
9202 if (last != NULL) {
9203 if (*last != NULL)
9204 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9205 (*last)->name);
9206 else
9207 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9208 }
9209#endif
9210 switch (axis) {
9211 case AXIS_ANCESTOR:
9212#ifdef DEBUG_STEP_NTH
9213 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9214#endif
9215 first = NULL;
9216 next = xmlXPathNextAncestor;
9217 break;
9218 case AXIS_ANCESTOR_OR_SELF:
9219#ifdef DEBUG_STEP_NTH
9220 xmlGenericError(xmlGenericErrorContext,
9221 "axis 'ancestors-or-self' ");
9222#endif
9223 first = NULL;
9224 next = xmlXPathNextAncestorOrSelf;
9225 break;
9226 case AXIS_ATTRIBUTE:
9227#ifdef DEBUG_STEP_NTH
9228 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9229#endif
9230 first = NULL;
9231 last = NULL;
9232 next = xmlXPathNextAttribute;
9233 break;
9234 case AXIS_CHILD:
9235#ifdef DEBUG_STEP_NTH
9236 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9237#endif
9238 last = NULL;
9239 next = xmlXPathNextChild;
9240 break;
9241 case AXIS_DESCENDANT:
9242#ifdef DEBUG_STEP_NTH
9243 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9244#endif
9245 last = NULL;
9246 next = xmlXPathNextDescendant;
9247 break;
9248 case AXIS_DESCENDANT_OR_SELF:
9249#ifdef DEBUG_STEP_NTH
9250 xmlGenericError(xmlGenericErrorContext,
9251 "axis 'descendant-or-self' ");
9252#endif
9253 last = NULL;
9254 next = xmlXPathNextDescendantOrSelf;
9255 break;
9256 case AXIS_FOLLOWING:
9257#ifdef DEBUG_STEP_NTH
9258 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9259#endif
9260 last = NULL;
9261 next = xmlXPathNextFollowing;
9262 break;
9263 case AXIS_FOLLOWING_SIBLING:
9264#ifdef DEBUG_STEP_NTH
9265 xmlGenericError(xmlGenericErrorContext,
9266 "axis 'following-siblings' ");
9267#endif
9268 last = NULL;
9269 next = xmlXPathNextFollowingSibling;
9270 break;
9271 case AXIS_NAMESPACE:
9272#ifdef DEBUG_STEP_NTH
9273 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9274#endif
9275 last = NULL;
9276 first = NULL;
9277 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9278 break;
9279 case AXIS_PARENT:
9280#ifdef DEBUG_STEP_NTH
9281 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9282#endif
9283 first = NULL;
9284 next = xmlXPathNextParent;
9285 break;
9286 case AXIS_PRECEDING:
9287#ifdef DEBUG_STEP_NTH
9288 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9289#endif
9290 first = NULL;
9291 next = xmlXPathNextPrecedingInternal;
9292 break;
9293 case AXIS_PRECEDING_SIBLING:
9294#ifdef DEBUG_STEP_NTH
9295 xmlGenericError(xmlGenericErrorContext,
9296 "axis 'preceding-sibling' ");
9297#endif
9298 first = NULL;
9299 next = xmlXPathNextPrecedingSibling;
9300 break;
9301 case AXIS_SELF:
9302#ifdef DEBUG_STEP_NTH
9303 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9304#endif
9305 first = NULL;
9306 last = NULL;
9307 next = xmlXPathNextSelf;
9308 break;
9309 }
9310 if (next == NULL)
9311 return(0);
9312
9313 nodelist = obj->nodesetval;
9314 if (nodelist == NULL) {
9315 xmlXPathFreeObject(obj);
9316 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9317 return(0);
9318 }
9319 addNode = xmlXPathNodeSetAddUnique;
9320#ifdef DEBUG_STEP_NTH
9321 xmlGenericError(xmlGenericErrorContext,
9322 " context contains %d nodes\n", nodelist->nodeNr);
9323 switch (test) {
9324 case NODE_TEST_NONE:
9325 xmlGenericError(xmlGenericErrorContext,
9326 " searching for none !!!\n");
9327 break;
9328 case NODE_TEST_TYPE:
9329 xmlGenericError(xmlGenericErrorContext,
9330 " searching for type %d\n", type);
9331 break;
9332 case NODE_TEST_PI:
9333 xmlGenericError(xmlGenericErrorContext,
9334 " searching for PI !!!\n");
9335 break;
9336 case NODE_TEST_ALL:
9337 xmlGenericError(xmlGenericErrorContext,
9338 " searching for *\n");
9339 break;
9340 case NODE_TEST_NS:
9341 xmlGenericError(xmlGenericErrorContext,
9342 " searching for namespace %s\n",
9343 prefix);
9344 break;
9345 case NODE_TEST_NAME:
9346 xmlGenericError(xmlGenericErrorContext,
9347 " searching for name %s\n", name);
9348 if (prefix != NULL)
9349 xmlGenericError(xmlGenericErrorContext,
9350 " with namespace %s\n", prefix);
9351 break;
9352 }
9353 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9354#endif
9355 /*
9356 * 2.3 Node Tests
9357 * - For the attribute axis, the principal node type is attribute.
9358 * - For the namespace axis, the principal node type is namespace.
9359 * - For other axes, the principal node type is element.
9360 *
9361 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009362 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009363 * select all element children of the context node
9364 */
9365 tmp = ctxt->context->node;
9366 list = xmlXPathNodeSetCreate(NULL);
9367 for (i = 0; i < nodelist->nodeNr; i++) {
9368 ctxt->context->node = nodelist->nodeTab[i];
9369
9370 cur = NULL;
9371 n = 0;
9372 do {
9373 cur = next(ctxt, cur);
9374 if (cur == NULL)
9375 break;
9376 if ((first != NULL) && (*first == cur))
9377 break;
9378 if (((t % 256) == 0) &&
9379 (first != NULL) && (*first != NULL) &&
9380 (xmlXPathCmpNodes(*first, cur) >= 0))
9381 break;
9382 if ((last != NULL) && (*last == cur))
9383 break;
9384 if (((t % 256) == 0) &&
9385 (last != NULL) && (*last != NULL) &&
9386 (xmlXPathCmpNodes(cur, *last) >= 0))
9387 break;
9388 t++;
9389 switch (test) {
9390 case NODE_TEST_NONE:
9391 ctxt->context->node = tmp;
9392 STRANGE return(0);
9393 case NODE_TEST_TYPE:
9394 if ((cur->type == type) ||
9395 ((type == NODE_TYPE_NODE) &&
9396 ((cur->type == XML_DOCUMENT_NODE) ||
9397 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9398 (cur->type == XML_ELEMENT_NODE) ||
9399 (cur->type == XML_PI_NODE) ||
9400 (cur->type == XML_COMMENT_NODE) ||
9401 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +00009402 (cur->type == XML_TEXT_NODE))) ||
9403 ((type == NODE_TYPE_TEXT) &&
9404 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009405 n++;
9406 if (n == indx)
9407 addNode(list, cur);
9408 }
9409 break;
9410 case NODE_TEST_PI:
9411 if (cur->type == XML_PI_NODE) {
9412 if ((name != NULL) &&
9413 (!xmlStrEqual(name, cur->name)))
9414 break;
9415 n++;
9416 if (n == indx)
9417 addNode(list, cur);
9418 }
9419 break;
9420 case NODE_TEST_ALL:
9421 if (axis == AXIS_ATTRIBUTE) {
9422 if (cur->type == XML_ATTRIBUTE_NODE) {
9423 n++;
9424 if (n == indx)
9425 addNode(list, cur);
9426 }
9427 } else if (axis == AXIS_NAMESPACE) {
9428 if (cur->type == XML_NAMESPACE_DECL) {
9429 n++;
9430 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009431 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9432 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009433 }
9434 } else {
9435 if (cur->type == XML_ELEMENT_NODE) {
9436 if (prefix == NULL) {
9437 n++;
9438 if (n == indx)
9439 addNode(list, cur);
9440 } else if ((cur->ns != NULL) &&
9441 (xmlStrEqual(URI, cur->ns->href))) {
9442 n++;
9443 if (n == indx)
9444 addNode(list, cur);
9445 }
9446 }
9447 }
9448 break;
9449 case NODE_TEST_NS:{
9450 TODO;
9451 break;
9452 }
9453 case NODE_TEST_NAME:
9454 switch (cur->type) {
9455 case XML_ELEMENT_NODE:
9456 if (xmlStrEqual(name, cur->name)) {
9457 if (prefix == NULL) {
9458 if (cur->ns == NULL) {
9459 n++;
9460 if (n == indx)
9461 addNode(list, cur);
9462 }
9463 } else {
9464 if ((cur->ns != NULL) &&
9465 (xmlStrEqual(URI,
9466 cur->ns->href))) {
9467 n++;
9468 if (n == indx)
9469 addNode(list, cur);
9470 }
9471 }
9472 }
9473 break;
9474 case XML_ATTRIBUTE_NODE:{
9475 xmlAttrPtr attr = (xmlAttrPtr) cur;
9476
9477 if (xmlStrEqual(name, attr->name)) {
9478 if (prefix == NULL) {
9479 if ((attr->ns == NULL) ||
9480 (attr->ns->prefix == NULL)) {
9481 n++;
9482 if (n == indx)
9483 addNode(list, cur);
9484 }
9485 } else {
9486 if ((attr->ns != NULL) &&
9487 (xmlStrEqual(URI,
9488 attr->ns->
9489 href))) {
9490 n++;
9491 if (n == indx)
9492 addNode(list, cur);
9493 }
9494 }
9495 }
9496 break;
9497 }
9498 case XML_NAMESPACE_DECL:
9499 if (cur->type == XML_NAMESPACE_DECL) {
9500 xmlNsPtr ns = (xmlNsPtr) cur;
9501
9502 if ((ns->prefix != NULL) && (name != NULL)
9503 && (xmlStrEqual(ns->prefix, name))) {
9504 n++;
9505 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009506 xmlXPathNodeSetAddNs(list,
9507 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009508 }
9509 }
9510 break;
9511 default:
9512 break;
9513 }
9514 break;
9515 break;
9516 }
9517 } while (n < indx);
9518 }
9519 ctxt->context->node = tmp;
9520#ifdef DEBUG_STEP_NTH
9521 xmlGenericError(xmlGenericErrorContext,
9522 "\nExamined %d nodes, found %d nodes at that step\n",
9523 t, list->nodeNr);
9524#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009525 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009526 if ((obj->boolval) && (obj->user != NULL)) {
9527 ctxt->value->boolval = 1;
9528 ctxt->value->user = obj->user;
9529 obj->user = NULL;
9530 obj->boolval = 0;
9531 }
9532 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009533 return(t);
9534}
9535
9536/**
9537 * xmlXPathCompOpEvalFirst:
9538 * @ctxt: the XPath parser context with the compiled expression
9539 * @op: an XPath compiled operation
9540 * @first: the first elem found so far
9541 *
9542 * Evaluate the Precompiled XPath operation searching only the first
9543 * element in document order
9544 *
9545 * Returns the number of examined objects.
9546 */
9547static int
9548xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9549 xmlXPathStepOpPtr op, xmlNodePtr * first)
9550{
9551 int total = 0, cur;
9552 xmlXPathCompExprPtr comp;
9553 xmlXPathObjectPtr arg1, arg2;
9554
Daniel Veillard556c6682001-10-06 09:59:51 +00009555 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009556 comp = ctxt->comp;
9557 switch (op->op) {
9558 case XPATH_OP_END:
9559 return (0);
9560 case XPATH_OP_UNION:
9561 total =
9562 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9563 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009564 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009565 if ((ctxt->value != NULL)
9566 && (ctxt->value->type == XPATH_NODESET)
9567 && (ctxt->value->nodesetval != NULL)
9568 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9569 /*
9570 * limit tree traversing to first node in the result
9571 */
9572 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9573 *first = ctxt->value->nodesetval->nodeTab[0];
9574 }
9575 cur =
9576 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9577 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009578 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009579 CHECK_TYPE0(XPATH_NODESET);
9580 arg2 = valuePop(ctxt);
9581
9582 CHECK_TYPE0(XPATH_NODESET);
9583 arg1 = valuePop(ctxt);
9584
9585 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9586 arg2->nodesetval);
9587 valuePush(ctxt, arg1);
9588 xmlXPathFreeObject(arg2);
9589 /* optimizer */
9590 if (total > cur)
9591 xmlXPathCompSwap(op);
9592 return (total + cur);
9593 case XPATH_OP_ROOT:
9594 xmlXPathRoot(ctxt);
9595 return (0);
9596 case XPATH_OP_NODE:
9597 if (op->ch1 != -1)
9598 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009599 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009600 if (op->ch2 != -1)
9601 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009602 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009603 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9604 return (total);
9605 case XPATH_OP_RESET:
9606 if (op->ch1 != -1)
9607 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009608 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009609 if (op->ch2 != -1)
9610 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009611 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009612 ctxt->context->node = NULL;
9613 return (total);
9614 case XPATH_OP_COLLECT:{
9615 if (op->ch1 == -1)
9616 return (total);
9617
9618 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009619 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009620
9621 /*
9622 * Optimization for [n] selection where n is a number
9623 */
9624 if ((op->ch2 != -1) &&
9625 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9626 (comp->steps[op->ch2].ch1 == -1) &&
9627 (comp->steps[op->ch2].ch2 != -1) &&
9628 (comp->steps[comp->steps[op->ch2].ch2].op ==
9629 XPATH_OP_VALUE)) {
9630 xmlXPathObjectPtr val;
9631
9632 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9633 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9634 int indx = (int) val->floatval;
9635
9636 if (val->floatval == (float) indx) {
9637 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9638 first, NULL);
9639 return (total);
9640 }
9641 }
9642 }
9643 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9644 return (total);
9645 }
9646 case XPATH_OP_VALUE:
9647 valuePush(ctxt,
9648 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9649 return (0);
9650 case XPATH_OP_SORT:
9651 if (op->ch1 != -1)
9652 total +=
9653 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9654 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009655 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009656 if ((ctxt->value != NULL)
9657 && (ctxt->value->type == XPATH_NODESET)
9658 && (ctxt->value->nodesetval != NULL))
9659 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9660 return (total);
9661 default:
9662 return (xmlXPathCompOpEval(ctxt, op));
9663 }
9664}
9665
9666/**
9667 * xmlXPathCompOpEvalLast:
9668 * @ctxt: the XPath parser context with the compiled expression
9669 * @op: an XPath compiled operation
9670 * @last: the last elem found so far
9671 *
9672 * Evaluate the Precompiled XPath operation searching only the last
9673 * element in document order
9674 *
9675 * Returns the number of node traversed
9676 */
9677static int
9678xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9679 xmlNodePtr * last)
9680{
9681 int total = 0, cur;
9682 xmlXPathCompExprPtr comp;
9683 xmlXPathObjectPtr arg1, arg2;
9684
Daniel Veillard556c6682001-10-06 09:59:51 +00009685 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009686 comp = ctxt->comp;
9687 switch (op->op) {
9688 case XPATH_OP_END:
9689 return (0);
9690 case XPATH_OP_UNION:
9691 total =
9692 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009693 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009694 if ((ctxt->value != NULL)
9695 && (ctxt->value->type == XPATH_NODESET)
9696 && (ctxt->value->nodesetval != NULL)
9697 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9698 /*
9699 * limit tree traversing to first node in the result
9700 */
9701 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9702 *last =
9703 ctxt->value->nodesetval->nodeTab[ctxt->value->
9704 nodesetval->nodeNr -
9705 1];
9706 }
9707 cur =
9708 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009709 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009710 if ((ctxt->value != NULL)
9711 && (ctxt->value->type == XPATH_NODESET)
9712 && (ctxt->value->nodesetval != NULL)
9713 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9714 }
9715 CHECK_TYPE0(XPATH_NODESET);
9716 arg2 = valuePop(ctxt);
9717
9718 CHECK_TYPE0(XPATH_NODESET);
9719 arg1 = valuePop(ctxt);
9720
9721 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9722 arg2->nodesetval);
9723 valuePush(ctxt, arg1);
9724 xmlXPathFreeObject(arg2);
9725 /* optimizer */
9726 if (total > cur)
9727 xmlXPathCompSwap(op);
9728 return (total + cur);
9729 case XPATH_OP_ROOT:
9730 xmlXPathRoot(ctxt);
9731 return (0);
9732 case XPATH_OP_NODE:
9733 if (op->ch1 != -1)
9734 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009735 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009736 if (op->ch2 != -1)
9737 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009738 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009739 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9740 return (total);
9741 case XPATH_OP_RESET:
9742 if (op->ch1 != -1)
9743 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009744 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009745 if (op->ch2 != -1)
9746 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009747 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009748 ctxt->context->node = NULL;
9749 return (total);
9750 case XPATH_OP_COLLECT:{
9751 if (op->ch1 == -1)
9752 return (0);
9753
9754 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009755 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009756
9757 /*
9758 * Optimization for [n] selection where n is a number
9759 */
9760 if ((op->ch2 != -1) &&
9761 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9762 (comp->steps[op->ch2].ch1 == -1) &&
9763 (comp->steps[op->ch2].ch2 != -1) &&
9764 (comp->steps[comp->steps[op->ch2].ch2].op ==
9765 XPATH_OP_VALUE)) {
9766 xmlXPathObjectPtr val;
9767
9768 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9769 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9770 int indx = (int) val->floatval;
9771
9772 if (val->floatval == (float) indx) {
9773 total +=
9774 xmlXPathNodeCollectAndTestNth(ctxt, op,
9775 indx, NULL,
9776 last);
9777 return (total);
9778 }
9779 }
9780 }
9781 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9782 return (total);
9783 }
9784 case XPATH_OP_VALUE:
9785 valuePush(ctxt,
9786 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9787 return (0);
9788 case XPATH_OP_SORT:
9789 if (op->ch1 != -1)
9790 total +=
9791 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9792 last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009793 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009794 if ((ctxt->value != NULL)
9795 && (ctxt->value->type == XPATH_NODESET)
9796 && (ctxt->value->nodesetval != NULL))
9797 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9798 return (total);
9799 default:
9800 return (xmlXPathCompOpEval(ctxt, op));
9801 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009802}
9803
Owen Taylor3473f882001-02-23 17:55:21 +00009804/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009805 * xmlXPathCompOpEval:
9806 * @ctxt: the XPath parser context with the compiled expression
9807 * @op: an XPath compiled operation
9808 *
9809 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009810 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009811 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009812static int
9813xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9814{
9815 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009816 int equal, ret;
9817 xmlXPathCompExprPtr comp;
9818 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009819 xmlNodePtr bak;
9820 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +00009821 int pp;
William M. Brack692092b2002-06-28 15:01:24 +00009822 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009823
Daniel Veillard556c6682001-10-06 09:59:51 +00009824 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009825 comp = ctxt->comp;
9826 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009827 case XPATH_OP_END:
9828 return (0);
9829 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009830 bakd = ctxt->context->doc;
9831 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009832 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009833 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009834 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009835 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009836 xmlXPathBooleanFunction(ctxt, 1);
9837 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9838 return (total);
9839 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009840 ctxt->context->doc = bakd;
9841 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009842 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009843 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009844 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009845 if (ctxt->error) {
9846 xmlXPathFreeObject(arg2);
9847 return(0);
9848 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009849 xmlXPathBooleanFunction(ctxt, 1);
9850 arg1 = valuePop(ctxt);
9851 arg1->boolval &= arg2->boolval;
9852 valuePush(ctxt, arg1);
9853 xmlXPathFreeObject(arg2);
9854 return (total);
9855 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009856 bakd = ctxt->context->doc;
9857 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009858 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009859 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009860 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009861 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009862 xmlXPathBooleanFunction(ctxt, 1);
9863 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9864 return (total);
9865 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009866 ctxt->context->doc = bakd;
9867 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009868 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009869 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009870 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009871 if (ctxt->error) {
9872 xmlXPathFreeObject(arg2);
9873 return(0);
9874 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009875 xmlXPathBooleanFunction(ctxt, 1);
9876 arg1 = valuePop(ctxt);
9877 arg1->boolval |= arg2->boolval;
9878 valuePush(ctxt, arg1);
9879 xmlXPathFreeObject(arg2);
9880 return (total);
9881 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009882 bakd = ctxt->context->doc;
9883 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009884 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009885 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009886 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009887 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009888 ctxt->context->doc = bakd;
9889 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009890 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009891 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009892 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009893 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +00009894 if (op->value)
9895 equal = xmlXPathEqualValues(ctxt);
9896 else
9897 equal = xmlXPathNotEqualValues(ctxt);
9898 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +00009899 return (total);
9900 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009901 bakd = ctxt->context->doc;
9902 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009903 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009904 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009905 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009906 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009907 ctxt->context->doc = bakd;
9908 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009909 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009910 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009911 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009912 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009913 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
9914 valuePush(ctxt, xmlXPathNewBoolean(ret));
9915 return (total);
9916 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009917 bakd = ctxt->context->doc;
9918 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009919 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009920 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009921 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009922 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009923 if (op->ch2 != -1) {
9924 ctxt->context->doc = bakd;
9925 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009926 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009927 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009928 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009929 }
Daniel Veillard556c6682001-10-06 09:59:51 +00009930 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009931 if (op->value == 0)
9932 xmlXPathSubValues(ctxt);
9933 else if (op->value == 1)
9934 xmlXPathAddValues(ctxt);
9935 else if (op->value == 2)
9936 xmlXPathValueFlipSign(ctxt);
9937 else if (op->value == 3) {
9938 CAST_TO_NUMBER;
9939 CHECK_TYPE0(XPATH_NUMBER);
9940 }
9941 return (total);
9942 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009943 bakd = ctxt->context->doc;
9944 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009945 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009946 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009947 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009948 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009949 ctxt->context->doc = bakd;
9950 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009951 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009952 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009953 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009954 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009955 if (op->value == 0)
9956 xmlXPathMultValues(ctxt);
9957 else if (op->value == 1)
9958 xmlXPathDivValues(ctxt);
9959 else if (op->value == 2)
9960 xmlXPathModValues(ctxt);
9961 return (total);
9962 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009963 bakd = ctxt->context->doc;
9964 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009965 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009966 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009967 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009968 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009969 ctxt->context->doc = bakd;
9970 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009971 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009972 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009973 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009974 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009975 CHECK_TYPE0(XPATH_NODESET);
9976 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009977
Daniel Veillardf06307e2001-07-03 10:35:50 +00009978 CHECK_TYPE0(XPATH_NODESET);
9979 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009980
Daniel Veillardf06307e2001-07-03 10:35:50 +00009981 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9982 arg2->nodesetval);
9983 valuePush(ctxt, arg1);
9984 xmlXPathFreeObject(arg2);
9985 return (total);
9986 case XPATH_OP_ROOT:
9987 xmlXPathRoot(ctxt);
9988 return (total);
9989 case XPATH_OP_NODE:
9990 if (op->ch1 != -1)
9991 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009992 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009993 if (op->ch2 != -1)
9994 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009995 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009996 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9997 return (total);
9998 case XPATH_OP_RESET:
9999 if (op->ch1 != -1)
10000 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010001 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010002 if (op->ch2 != -1)
10003 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010004 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010005 ctxt->context->node = NULL;
10006 return (total);
10007 case XPATH_OP_COLLECT:{
10008 if (op->ch1 == -1)
10009 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010010
Daniel Veillardf06307e2001-07-03 10:35:50 +000010011 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010012 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010013
Daniel Veillardf06307e2001-07-03 10:35:50 +000010014 /*
10015 * Optimization for [n] selection where n is a number
10016 */
10017 if ((op->ch2 != -1) &&
10018 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10019 (comp->steps[op->ch2].ch1 == -1) &&
10020 (comp->steps[op->ch2].ch2 != -1) &&
10021 (comp->steps[comp->steps[op->ch2].ch2].op ==
10022 XPATH_OP_VALUE)) {
10023 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +000010024
Daniel Veillardf06307e2001-07-03 10:35:50 +000010025 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10026 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10027 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010028
Daniel Veillardf06307e2001-07-03 10:35:50 +000010029 if (val->floatval == (float) indx) {
10030 total +=
10031 xmlXPathNodeCollectAndTestNth(ctxt, op,
10032 indx, NULL,
10033 NULL);
10034 return (total);
10035 }
10036 }
10037 }
10038 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
10039 return (total);
10040 }
10041 case XPATH_OP_VALUE:
10042 valuePush(ctxt,
10043 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10044 return (total);
10045 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000010046 xmlXPathObjectPtr val;
10047
Daniel Veillardf06307e2001-07-03 10:35:50 +000010048 if (op->ch1 != -1)
10049 total +=
10050 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010051 if (op->value5 == NULL) {
10052 val = xmlXPathVariableLookup(ctxt->context, op->value4);
10053 if (val == NULL) {
10054 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10055 return(0);
10056 }
10057 valuePush(ctxt, val);
10058 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010059 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010060
Daniel Veillardf06307e2001-07-03 10:35:50 +000010061 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10062 if (URI == NULL) {
10063 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010064 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010065 op->value4, op->value5);
10066 return (total);
10067 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010068 val = xmlXPathVariableLookupNS(ctxt->context,
10069 op->value4, URI);
10070 if (val == NULL) {
10071 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10072 return(0);
10073 }
10074 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010075 }
10076 return (total);
10077 }
10078 case XPATH_OP_FUNCTION:{
10079 xmlXPathFunction func;
10080 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000010081 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010082
10083 if (op->ch1 != -1)
10084 total +=
10085 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010086 if (ctxt->valueNr < op->value) {
10087 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010088 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010089 ctxt->error = XPATH_INVALID_OPERAND;
10090 return (total);
10091 }
10092 for (i = 0; i < op->value; i++)
10093 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10094 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010095 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010096 ctxt->error = XPATH_INVALID_OPERAND;
10097 return (total);
10098 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010099 if (op->cache != NULL)
10100 func = (xmlXPathFunction) op->cache;
10101 else {
10102 const xmlChar *URI = NULL;
10103
10104 if (op->value5 == NULL)
10105 func =
10106 xmlXPathFunctionLookup(ctxt->context,
10107 op->value4);
10108 else {
10109 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10110 if (URI == NULL) {
10111 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010112 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010113 op->value4, op->value5);
10114 return (total);
10115 }
10116 func = xmlXPathFunctionLookupNS(ctxt->context,
10117 op->value4, URI);
10118 }
10119 if (func == NULL) {
10120 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010121 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010122 op->value4);
10123 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010124 }
10125 op->cache = (void *) func;
10126 op->cacheURI = (void *) URI;
10127 }
10128 oldFunc = ctxt->context->function;
10129 oldFuncURI = ctxt->context->functionURI;
10130 ctxt->context->function = op->value4;
10131 ctxt->context->functionURI = op->cacheURI;
10132 func(ctxt, op->value);
10133 ctxt->context->function = oldFunc;
10134 ctxt->context->functionURI = oldFuncURI;
10135 return (total);
10136 }
10137 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000010138 bakd = ctxt->context->doc;
10139 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010140 if (op->ch1 != -1)
10141 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010142 ctxt->context->doc = bakd;
10143 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010144 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010145 if (op->ch2 != -1)
10146 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010147 ctxt->context->doc = bakd;
10148 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010149 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010150 return (total);
10151 case XPATH_OP_PREDICATE:
10152 case XPATH_OP_FILTER:{
10153 xmlXPathObjectPtr res;
10154 xmlXPathObjectPtr obj, tmp;
10155 xmlNodeSetPtr newset = NULL;
10156 xmlNodeSetPtr oldset;
10157 xmlNodePtr oldnode;
10158 int i;
10159
10160 /*
10161 * Optimization for ()[1] selection i.e. the first elem
10162 */
10163 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10164 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10165 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10166 xmlXPathObjectPtr val;
10167
10168 val = comp->steps[op->ch2].value4;
10169 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10170 (val->floatval == 1.0)) {
10171 xmlNodePtr first = NULL;
10172
10173 total +=
10174 xmlXPathCompOpEvalFirst(ctxt,
10175 &comp->steps[op->ch1],
10176 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010177 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010178 /*
10179 * The nodeset should be in document order,
10180 * Keep only the first value
10181 */
10182 if ((ctxt->value != NULL) &&
10183 (ctxt->value->type == XPATH_NODESET) &&
10184 (ctxt->value->nodesetval != NULL) &&
10185 (ctxt->value->nodesetval->nodeNr > 1))
10186 ctxt->value->nodesetval->nodeNr = 1;
10187 return (total);
10188 }
10189 }
10190 /*
10191 * Optimization for ()[last()] selection i.e. the last elem
10192 */
10193 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10194 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10195 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10196 int f = comp->steps[op->ch2].ch1;
10197
10198 if ((f != -1) &&
10199 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10200 (comp->steps[f].value5 == NULL) &&
10201 (comp->steps[f].value == 0) &&
10202 (comp->steps[f].value4 != NULL) &&
10203 (xmlStrEqual
10204 (comp->steps[f].value4, BAD_CAST "last"))) {
10205 xmlNodePtr last = NULL;
10206
10207 total +=
10208 xmlXPathCompOpEvalLast(ctxt,
10209 &comp->steps[op->ch1],
10210 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010211 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010212 /*
10213 * The nodeset should be in document order,
10214 * Keep only the last value
10215 */
10216 if ((ctxt->value != NULL) &&
10217 (ctxt->value->type == XPATH_NODESET) &&
10218 (ctxt->value->nodesetval != NULL) &&
10219 (ctxt->value->nodesetval->nodeTab != NULL) &&
10220 (ctxt->value->nodesetval->nodeNr > 1)) {
10221 ctxt->value->nodesetval->nodeTab[0] =
10222 ctxt->value->nodesetval->nodeTab[ctxt->
10223 value->
10224 nodesetval->
10225 nodeNr -
10226 1];
10227 ctxt->value->nodesetval->nodeNr = 1;
10228 }
10229 return (total);
10230 }
10231 }
10232
10233 if (op->ch1 != -1)
10234 total +=
10235 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010236 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010237 if (op->ch2 == -1)
10238 return (total);
10239 if (ctxt->value == NULL)
10240 return (total);
10241
10242 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010243
10244#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010245 /*
10246 * Hum are we filtering the result of an XPointer expression
10247 */
10248 if (ctxt->value->type == XPATH_LOCATIONSET) {
10249 xmlLocationSetPtr newlocset = NULL;
10250 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010251
Daniel Veillardf06307e2001-07-03 10:35:50 +000010252 /*
10253 * Extract the old locset, and then evaluate the result of the
10254 * expression for all the element in the locset. use it to grow
10255 * up a new locset.
10256 */
10257 CHECK_TYPE0(XPATH_LOCATIONSET);
10258 obj = valuePop(ctxt);
10259 oldlocset = obj->user;
10260 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010261
Daniel Veillardf06307e2001-07-03 10:35:50 +000010262 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10263 ctxt->context->contextSize = 0;
10264 ctxt->context->proximityPosition = 0;
10265 if (op->ch2 != -1)
10266 total +=
10267 xmlXPathCompOpEval(ctxt,
10268 &comp->steps[op->ch2]);
10269 res = valuePop(ctxt);
10270 if (res != NULL)
10271 xmlXPathFreeObject(res);
10272 valuePush(ctxt, obj);
10273 CHECK_ERROR0;
10274 return (total);
10275 }
10276 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010277
Daniel Veillardf06307e2001-07-03 10:35:50 +000010278 for (i = 0; i < oldlocset->locNr; i++) {
10279 /*
10280 * Run the evaluation with a node list made of a
10281 * single item in the nodelocset.
10282 */
10283 ctxt->context->node = oldlocset->locTab[i]->user;
10284 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10285 valuePush(ctxt, tmp);
10286 ctxt->context->contextSize = oldlocset->locNr;
10287 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010288
Daniel Veillardf06307e2001-07-03 10:35:50 +000010289 if (op->ch2 != -1)
10290 total +=
10291 xmlXPathCompOpEval(ctxt,
10292 &comp->steps[op->ch2]);
10293 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010294
Daniel Veillardf06307e2001-07-03 10:35:50 +000010295 /*
10296 * The result of the evaluation need to be tested to
10297 * decided whether the filter succeeded or not
10298 */
10299 res = valuePop(ctxt);
10300 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10301 xmlXPtrLocationSetAdd(newlocset,
10302 xmlXPathObjectCopy
10303 (oldlocset->locTab[i]));
10304 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010305
Daniel Veillardf06307e2001-07-03 10:35:50 +000010306 /*
10307 * Cleanup
10308 */
10309 if (res != NULL)
10310 xmlXPathFreeObject(res);
10311 if (ctxt->value == tmp) {
10312 res = valuePop(ctxt);
10313 xmlXPathFreeObject(res);
10314 }
10315
10316 ctxt->context->node = NULL;
10317 }
10318
10319 /*
10320 * The result is used as the new evaluation locset.
10321 */
10322 xmlXPathFreeObject(obj);
10323 ctxt->context->node = NULL;
10324 ctxt->context->contextSize = -1;
10325 ctxt->context->proximityPosition = -1;
10326 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10327 ctxt->context->node = oldnode;
10328 return (total);
10329 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010330#endif /* LIBXML_XPTR_ENABLED */
10331
Daniel Veillardf06307e2001-07-03 10:35:50 +000010332 /*
10333 * Extract the old set, and then evaluate the result of the
10334 * expression for all the element in the set. use it to grow
10335 * up a new set.
10336 */
10337 CHECK_TYPE0(XPATH_NODESET);
10338 obj = valuePop(ctxt);
10339 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010340
Daniel Veillardf06307e2001-07-03 10:35:50 +000010341 oldnode = ctxt->context->node;
10342 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010343
Daniel Veillardf06307e2001-07-03 10:35:50 +000010344 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10345 ctxt->context->contextSize = 0;
10346 ctxt->context->proximityPosition = 0;
10347 if (op->ch2 != -1)
10348 total +=
10349 xmlXPathCompOpEval(ctxt,
10350 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010351 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010352 res = valuePop(ctxt);
10353 if (res != NULL)
10354 xmlXPathFreeObject(res);
10355 valuePush(ctxt, obj);
10356 ctxt->context->node = oldnode;
10357 CHECK_ERROR0;
10358 } else {
10359 /*
10360 * Initialize the new set.
10361 */
10362 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010363
Daniel Veillardf06307e2001-07-03 10:35:50 +000010364 for (i = 0; i < oldset->nodeNr; i++) {
10365 /*
10366 * Run the evaluation with a node list made of
10367 * a single item in the nodeset.
10368 */
10369 ctxt->context->node = oldset->nodeTab[i];
10370 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10371 valuePush(ctxt, tmp);
10372 ctxt->context->contextSize = oldset->nodeNr;
10373 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010374
Daniel Veillardf06307e2001-07-03 10:35:50 +000010375 if (op->ch2 != -1)
10376 total +=
10377 xmlXPathCompOpEval(ctxt,
10378 &comp->steps[op->ch2]);
10379 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010380
Daniel Veillardf06307e2001-07-03 10:35:50 +000010381 /*
10382 * The result of the evaluation need to be tested to
10383 * decided whether the filter succeeded or not
10384 */
10385 res = valuePop(ctxt);
10386 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10387 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10388 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010389
Daniel Veillardf06307e2001-07-03 10:35:50 +000010390 /*
10391 * Cleanup
10392 */
10393 if (res != NULL)
10394 xmlXPathFreeObject(res);
10395 if (ctxt->value == tmp) {
10396 res = valuePop(ctxt);
10397 xmlXPathFreeObject(res);
10398 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010399
Daniel Veillardf06307e2001-07-03 10:35:50 +000010400 ctxt->context->node = NULL;
10401 }
10402
10403 /*
10404 * The result is used as the new evaluation set.
10405 */
10406 xmlXPathFreeObject(obj);
10407 ctxt->context->node = NULL;
10408 ctxt->context->contextSize = -1;
10409 ctxt->context->proximityPosition = -1;
10410 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10411 }
10412 ctxt->context->node = oldnode;
10413 return (total);
10414 }
10415 case XPATH_OP_SORT:
10416 if (op->ch1 != -1)
10417 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010418 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010419 if ((ctxt->value != NULL) &&
10420 (ctxt->value->type == XPATH_NODESET) &&
10421 (ctxt->value->nodesetval != NULL))
10422 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10423 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010424#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010425 case XPATH_OP_RANGETO:{
10426 xmlXPathObjectPtr range;
10427 xmlXPathObjectPtr res, obj;
10428 xmlXPathObjectPtr tmp;
10429 xmlLocationSetPtr newset = NULL;
10430 xmlNodeSetPtr oldset;
10431 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010432
Daniel Veillardf06307e2001-07-03 10:35:50 +000010433 if (op->ch1 != -1)
10434 total +=
10435 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10436 if (op->ch2 == -1)
10437 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010438
Daniel Veillardf06307e2001-07-03 10:35:50 +000010439 CHECK_TYPE0(XPATH_NODESET);
10440 obj = valuePop(ctxt);
10441 oldset = obj->nodesetval;
10442 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010443
Daniel Veillardf06307e2001-07-03 10:35:50 +000010444 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010445
Daniel Veillardf06307e2001-07-03 10:35:50 +000010446 if (oldset != NULL) {
10447 for (i = 0; i < oldset->nodeNr; i++) {
10448 /*
10449 * Run the evaluation with a node list made of a single item
10450 * in the nodeset.
10451 */
10452 ctxt->context->node = oldset->nodeTab[i];
10453 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10454 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010455
Daniel Veillardf06307e2001-07-03 10:35:50 +000010456 if (op->ch2 != -1)
10457 total +=
10458 xmlXPathCompOpEval(ctxt,
10459 &comp->steps[op->ch2]);
10460 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010461
Daniel Veillardf06307e2001-07-03 10:35:50 +000010462 /*
10463 * The result of the evaluation need to be tested to
10464 * decided whether the filter succeeded or not
10465 */
10466 res = valuePop(ctxt);
10467 range =
10468 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10469 res);
10470 if (range != NULL) {
10471 xmlXPtrLocationSetAdd(newset, range);
10472 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010473
Daniel Veillardf06307e2001-07-03 10:35:50 +000010474 /*
10475 * Cleanup
10476 */
10477 if (res != NULL)
10478 xmlXPathFreeObject(res);
10479 if (ctxt->value == tmp) {
10480 res = valuePop(ctxt);
10481 xmlXPathFreeObject(res);
10482 }
10483
10484 ctxt->context->node = NULL;
10485 }
10486 }
10487
10488 /*
10489 * The result is used as the new evaluation set.
10490 */
10491 xmlXPathFreeObject(obj);
10492 ctxt->context->node = NULL;
10493 ctxt->context->contextSize = -1;
10494 ctxt->context->proximityPosition = -1;
10495 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
10496 return (total);
10497 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010498#endif /* LIBXML_XPTR_ENABLED */
10499 }
10500 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010501 "XPath: unknown precompiled operation %d\n", op->op);
10502 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010503}
10504
10505/**
10506 * xmlXPathRunEval:
10507 * @ctxt: the XPath parser context with the compiled expression
10508 *
10509 * Evaluate the Precompiled XPath expression in the given context.
10510 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010511static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010512xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10513 xmlXPathCompExprPtr comp;
10514
10515 if ((ctxt == NULL) || (ctxt->comp == NULL))
10516 return;
10517
10518 if (ctxt->valueTab == NULL) {
10519 /* Allocate the value stack */
10520 ctxt->valueTab = (xmlXPathObjectPtr *)
10521 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10522 if (ctxt->valueTab == NULL) {
10523 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010524 }
10525 ctxt->valueNr = 0;
10526 ctxt->valueMax = 10;
10527 ctxt->value = NULL;
10528 }
10529 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000010530 if(comp->last < 0) {
10531 xmlGenericError(xmlGenericErrorContext,
10532 "xmlXPathRunEval: last is less than zero\n");
10533 return;
10534 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010535 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10536}
10537
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010538/************************************************************************
10539 * *
10540 * Public interfaces *
10541 * *
10542 ************************************************************************/
10543
10544/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010545 * xmlXPathEvalPredicate:
10546 * @ctxt: the XPath context
10547 * @res: the Predicate Expression evaluation result
10548 *
10549 * Evaluate a predicate result for the current node.
10550 * A PredicateExpr is evaluated by evaluating the Expr and converting
10551 * the result to a boolean. If the result is a number, the result will
10552 * be converted to true if the number is equal to the position of the
10553 * context node in the context node list (as returned by the position
10554 * function) and will be converted to false otherwise; if the result
10555 * is not a number, then the result will be converted as if by a call
10556 * to the boolean function.
10557 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010558 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010559 */
10560int
10561xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
10562 if (res == NULL) return(0);
10563 switch (res->type) {
10564 case XPATH_BOOLEAN:
10565 return(res->boolval);
10566 case XPATH_NUMBER:
10567 return(res->floatval == ctxt->proximityPosition);
10568 case XPATH_NODESET:
10569 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010570 if (res->nodesetval == NULL)
10571 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010572 return(res->nodesetval->nodeNr != 0);
10573 case XPATH_STRING:
10574 return((res->stringval != NULL) &&
10575 (xmlStrlen(res->stringval) != 0));
10576 default:
10577 STRANGE
10578 }
10579 return(0);
10580}
10581
10582/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010583 * xmlXPathEvaluatePredicateResult:
10584 * @ctxt: the XPath Parser context
10585 * @res: the Predicate Expression evaluation result
10586 *
10587 * Evaluate a predicate result for the current node.
10588 * A PredicateExpr is evaluated by evaluating the Expr and converting
10589 * the result to a boolean. If the result is a number, the result will
10590 * be converted to true if the number is equal to the position of the
10591 * context node in the context node list (as returned by the position
10592 * function) and will be converted to false otherwise; if the result
10593 * is not a number, then the result will be converted as if by a call
10594 * to the boolean function.
10595 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010596 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010597 */
10598int
10599xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10600 xmlXPathObjectPtr res) {
10601 if (res == NULL) return(0);
10602 switch (res->type) {
10603 case XPATH_BOOLEAN:
10604 return(res->boolval);
10605 case XPATH_NUMBER:
10606 return(res->floatval == ctxt->context->proximityPosition);
10607 case XPATH_NODESET:
10608 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000010609 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000010610 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010611 return(res->nodesetval->nodeNr != 0);
10612 case XPATH_STRING:
10613 return((res->stringval != NULL) &&
10614 (xmlStrlen(res->stringval) != 0));
10615 default:
10616 STRANGE
10617 }
10618 return(0);
10619}
10620
10621/**
10622 * xmlXPathCompile:
10623 * @str: the XPath expression
10624 *
10625 * Compile an XPath expression
10626 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000010627 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010628 * the caller has to free the object.
10629 */
10630xmlXPathCompExprPtr
10631xmlXPathCompile(const xmlChar *str) {
10632 xmlXPathParserContextPtr ctxt;
10633 xmlXPathCompExprPtr comp;
10634
10635 xmlXPathInit();
10636
10637 ctxt = xmlXPathNewParserContext(str, NULL);
10638 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010639
Daniel Veillard40af6492001-04-22 08:50:55 +000010640 if (*ctxt->cur != 0) {
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010641 /*
10642 * aleksey: in some cases this line prints *second* error message
10643 * (see bug #78858) and probably this should be fixed.
10644 * However, we are not sure that all error messages are printed
10645 * out in other places. It's not critical so we leave it as-is for now
10646 */
Daniel Veillard40af6492001-04-22 08:50:55 +000010647 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10648 comp = NULL;
10649 } else {
10650 comp = ctxt->comp;
10651 ctxt->comp = NULL;
10652 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010653 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010654 if (comp != NULL) {
Daniel Veillardceb09b92002-10-04 11:46:37 +000010655 comp->expr = xmlStrdup(str);
10656#ifdef DEBUG_EVAL_COUNTS
Daniel Veillardf06307e2001-07-03 10:35:50 +000010657 comp->string = xmlStrdup(str);
10658 comp->nb = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010659#endif
Daniel Veillardceb09b92002-10-04 11:46:37 +000010660 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010661 return(comp);
10662}
10663
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010664/**
10665 * xmlXPathCompiledEval:
10666 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000010667 * @ctx: the XPath context
10668 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010669 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000010670 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010671 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000010672 * the caller has to free the object.
10673 */
10674xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010675xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000010676 xmlXPathParserContextPtr ctxt;
10677 xmlXPathObjectPtr res, tmp, init = NULL;
10678 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000010679#ifndef LIBXML_THREAD_ENABLED
10680 static int reentance = 0;
10681#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010682
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010683 if ((comp == NULL) || (ctx == NULL))
10684 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010685 xmlXPathInit();
10686
10687 CHECK_CONTEXT(ctx)
10688
Daniel Veillard81463942001-10-16 12:34:39 +000010689#ifndef LIBXML_THREAD_ENABLED
10690 reentance++;
10691 if (reentance > 1)
10692 xmlXPathDisableOptimizer = 1;
10693#endif
10694
Daniel Veillardf06307e2001-07-03 10:35:50 +000010695#ifdef DEBUG_EVAL_COUNTS
10696 comp->nb++;
10697 if ((comp->string != NULL) && (comp->nb > 100)) {
10698 fprintf(stderr, "100 x %s\n", comp->string);
10699 comp->nb = 0;
10700 }
10701#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010702 ctxt = xmlXPathCompParserContext(comp, ctx);
10703 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010704
10705 if (ctxt->value == NULL) {
10706 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010707 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000010708 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000010709 } else {
10710 res = valuePop(ctxt);
10711 }
10712
Daniel Veillardf06307e2001-07-03 10:35:50 +000010713
Owen Taylor3473f882001-02-23 17:55:21 +000010714 do {
10715 tmp = valuePop(ctxt);
10716 if (tmp != NULL) {
10717 if (tmp != init)
10718 stack++;
10719 xmlXPathFreeObject(tmp);
10720 }
10721 } while (tmp != NULL);
10722 if ((stack != 0) && (res != NULL)) {
10723 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010724 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000010725 stack);
10726 }
10727 if (ctxt->error != XPATH_EXPRESSION_OK) {
10728 xmlXPathFreeObject(res);
10729 res = NULL;
10730 }
10731
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010732
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010733 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010734 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000010735#ifndef LIBXML_THREAD_ENABLED
10736 reentance--;
10737#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010738 return(res);
10739}
10740
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010741/**
10742 * xmlXPathEvalExpr:
10743 * @ctxt: the XPath Parser context
10744 *
10745 * Parse and evaluate an XPath expression in the given context,
10746 * then push the result on the context stack
10747 */
10748void
10749xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
10750 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010751 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010752 xmlXPathRunEval(ctxt);
10753}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010754
10755/**
10756 * xmlXPathEval:
10757 * @str: the XPath expression
10758 * @ctx: the XPath context
10759 *
10760 * Evaluate the XPath Location Path in the given context.
10761 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010762 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010763 * the caller has to free the object.
10764 */
10765xmlXPathObjectPtr
10766xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
10767 xmlXPathParserContextPtr ctxt;
10768 xmlXPathObjectPtr res, tmp, init = NULL;
10769 int stack = 0;
10770
10771 xmlXPathInit();
10772
10773 CHECK_CONTEXT(ctx)
10774
10775 ctxt = xmlXPathNewParserContext(str, ctx);
10776 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010777
10778 if (ctxt->value == NULL) {
10779 xmlGenericError(xmlGenericErrorContext,
10780 "xmlXPathEval: evaluation failed\n");
10781 res = NULL;
10782 } else if (*ctxt->cur != 0) {
10783 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10784 res = NULL;
10785 } else {
10786 res = valuePop(ctxt);
10787 }
10788
10789 do {
10790 tmp = valuePop(ctxt);
10791 if (tmp != NULL) {
10792 if (tmp != init)
10793 stack++;
10794 xmlXPathFreeObject(tmp);
10795 }
10796 } while (tmp != NULL);
10797 if ((stack != 0) && (res != NULL)) {
10798 xmlGenericError(xmlGenericErrorContext,
10799 "xmlXPathEval: %d object left on the stack\n",
10800 stack);
10801 }
10802 if (ctxt->error != XPATH_EXPRESSION_OK) {
10803 xmlXPathFreeObject(res);
10804 res = NULL;
10805 }
10806
Owen Taylor3473f882001-02-23 17:55:21 +000010807 xmlXPathFreeParserContext(ctxt);
10808 return(res);
10809}
10810
10811/**
10812 * xmlXPathEvalExpression:
10813 * @str: the XPath expression
10814 * @ctxt: the XPath context
10815 *
10816 * Evaluate the XPath expression in the given context.
10817 *
10818 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
10819 * the caller has to free the object.
10820 */
10821xmlXPathObjectPtr
10822xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
10823 xmlXPathParserContextPtr pctxt;
10824 xmlXPathObjectPtr res, tmp;
10825 int stack = 0;
10826
10827 xmlXPathInit();
10828
10829 CHECK_CONTEXT(ctxt)
10830
10831 pctxt = xmlXPathNewParserContext(str, ctxt);
10832 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010833
10834 if (*pctxt->cur != 0) {
10835 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10836 res = NULL;
10837 } else {
10838 res = valuePop(pctxt);
10839 }
10840 do {
10841 tmp = valuePop(pctxt);
10842 if (tmp != NULL) {
10843 xmlXPathFreeObject(tmp);
10844 stack++;
10845 }
10846 } while (tmp != NULL);
10847 if ((stack != 0) && (res != NULL)) {
10848 xmlGenericError(xmlGenericErrorContext,
10849 "xmlXPathEvalExpression: %d object left on the stack\n",
10850 stack);
10851 }
10852 xmlXPathFreeParserContext(pctxt);
10853 return(res);
10854}
10855
Daniel Veillard42766c02002-08-22 20:52:17 +000010856/************************************************************************
10857 * *
10858 * Extra functions not pertaining to the XPath spec *
10859 * *
10860 ************************************************************************/
10861/**
10862 * xmlXPathEscapeUriFunction:
10863 * @ctxt: the XPath Parser context
10864 * @nargs: the number of arguments
10865 *
10866 * Implement the escape-uri() XPath function
10867 * string escape-uri(string $str, bool $escape-reserved)
10868 *
10869 * This function applies the URI escaping rules defined in section 2 of [RFC
10870 * 2396] to the string supplied as $uri-part, which typically represents all
10871 * or part of a URI. The effect of the function is to replace any special
10872 * character in the string by an escape sequence of the form %xx%yy...,
10873 * where xxyy... is the hexadecimal representation of the octets used to
10874 * represent the character in UTF-8.
10875 *
10876 * The set of characters that are escaped depends on the setting of the
10877 * boolean argument $escape-reserved.
10878 *
10879 * If $escape-reserved is true, all characters are escaped other than lower
10880 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
10881 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
10882 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
10883 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
10884 * A-F).
10885 *
10886 * If $escape-reserved is false, the behavior differs in that characters
10887 * referred to in [RFC 2396] as reserved characters are not escaped. These
10888 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
10889 *
10890 * [RFC 2396] does not define whether escaped URIs should use lower case or
10891 * upper case for hexadecimal digits. To ensure that escaped URIs can be
10892 * compared using string comparison functions, this function must always use
10893 * the upper-case letters A-F.
10894 *
10895 * Generally, $escape-reserved should be set to true when escaping a string
10896 * that is to form a single part of a URI, and to false when escaping an
10897 * entire URI or URI reference.
10898 *
10899 * In the case of non-ascii characters, the string is encoded according to
10900 * utf-8 and then converted according to RFC 2396.
10901 *
10902 * Examples
10903 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
10904 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
10905 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
10906 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
10907 *
10908 */
Daniel Veillard118aed72002-09-24 14:13:13 +000010909static void
Daniel Veillard42766c02002-08-22 20:52:17 +000010910xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
10911 xmlXPathObjectPtr str;
10912 int escape_reserved;
10913 xmlBufferPtr target;
10914 xmlChar *cptr;
10915 xmlChar escape[4];
10916
10917 CHECK_ARITY(2);
10918
10919 escape_reserved = xmlXPathPopBoolean(ctxt);
10920
10921 CAST_TO_STRING;
10922 str = valuePop(ctxt);
10923
10924 target = xmlBufferCreate();
10925
10926 escape[0] = '%';
10927 escape[3] = 0;
10928
10929 if (target) {
10930 for (cptr = str->stringval; *cptr; cptr++) {
10931 if ((*cptr >= 'A' && *cptr <= 'Z') ||
10932 (*cptr >= 'a' && *cptr <= 'z') ||
10933 (*cptr >= '0' && *cptr <= '9') ||
10934 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
10935 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
10936 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
10937 (*cptr == '%' &&
10938 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
10939 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
10940 (cptr[1] >= '0' && cptr[1] <= '9')) &&
10941 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
10942 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
10943 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
10944 (!escape_reserved &&
10945 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
10946 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
10947 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
10948 *cptr == ','))) {
10949 xmlBufferAdd(target, cptr, 1);
10950 } else {
10951 if ((*cptr >> 4) < 10)
10952 escape[1] = '0' + (*cptr >> 4);
10953 else
10954 escape[1] = 'A' - 10 + (*cptr >> 4);
10955 if ((*cptr & 0xF) < 10)
10956 escape[2] = '0' + (*cptr & 0xF);
10957 else
10958 escape[2] = 'A' - 10 + (*cptr & 0xF);
10959
10960 xmlBufferAdd(target, &escape[0], 3);
10961 }
10962 }
10963 }
10964 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
10965 xmlBufferFree(target);
10966 xmlXPathFreeObject(str);
10967}
10968
Owen Taylor3473f882001-02-23 17:55:21 +000010969/**
10970 * xmlXPathRegisterAllFunctions:
10971 * @ctxt: the XPath context
10972 *
10973 * Registers all default XPath functions in this context
10974 */
10975void
10976xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
10977{
10978 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
10979 xmlXPathBooleanFunction);
10980 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
10981 xmlXPathCeilingFunction);
10982 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
10983 xmlXPathCountFunction);
10984 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
10985 xmlXPathConcatFunction);
10986 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
10987 xmlXPathContainsFunction);
10988 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
10989 xmlXPathIdFunction);
10990 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
10991 xmlXPathFalseFunction);
10992 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
10993 xmlXPathFloorFunction);
10994 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
10995 xmlXPathLastFunction);
10996 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
10997 xmlXPathLangFunction);
10998 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
10999 xmlXPathLocalNameFunction);
11000 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
11001 xmlXPathNotFunction);
11002 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
11003 xmlXPathNameFunction);
11004 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
11005 xmlXPathNamespaceURIFunction);
11006 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
11007 xmlXPathNormalizeFunction);
11008 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
11009 xmlXPathNumberFunction);
11010 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
11011 xmlXPathPositionFunction);
11012 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
11013 xmlXPathRoundFunction);
11014 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
11015 xmlXPathStringFunction);
11016 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
11017 xmlXPathStringLengthFunction);
11018 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
11019 xmlXPathStartsWithFunction);
11020 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
11021 xmlXPathSubstringFunction);
11022 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
11023 xmlXPathSubstringBeforeFunction);
11024 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
11025 xmlXPathSubstringAfterFunction);
11026 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
11027 xmlXPathSumFunction);
11028 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
11029 xmlXPathTrueFunction);
11030 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
11031 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000011032
11033 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
11034 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
11035 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000011036}
11037
11038#endif /* LIBXML_XPATH_ENABLED */