blob: 69a39108419b56df9966b7edf2820b260ddfdb2a [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;
1355 xmlNodePtr cur, root;
1356
1357 if ((node1 == NULL) || (node2 == NULL))
1358 return(-2);
1359 /*
1360 * a couple of optimizations which will avoid computations in most cases
1361 */
1362 if (node1 == node2)
1363 return(0);
Daniel Veillardb33c2012001-04-25 12:59:04 +00001364 if ((node1->type == XML_NAMESPACE_DECL) ||
1365 (node2->type == XML_NAMESPACE_DECL))
1366 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001367 if (node1 == node2->prev)
1368 return(1);
1369 if (node1 == node2->next)
1370 return(-1);
1371
Daniel Veillard68e9e742002-11-16 15:35:11 +00001372#if 0
1373 Unfortunately this does not work. Line number in entities reset
1374 to 1 within the entity :-(
1375
Owen Taylor3473f882001-02-23 17:55:21 +00001376 /*
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001377 * Speedup using line numbers if availble.
1378 */
1379 if ((node1->type == XML_ELEMENT_NODE) &&
1380 (node2->type == XML_ELEMENT_NODE) &&
1381 (0 != (int) node1->content) && (0 != (int) node2->content)) {
1382 int l1, l2;
1383 l1 = (int) node1->content;
1384 l2 = (int) node2->content;
1385 if (l1 < l2)
1386 return(1);
1387 if (l1 > l2)
1388 return(-1);
1389 }
Daniel Veillard68e9e742002-11-16 15:35:11 +00001390#endif
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001391 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001392 * compute depth to root
1393 */
1394 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1395 if (cur == node1)
1396 return(1);
1397 depth2++;
1398 }
1399 root = cur;
1400 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1401 if (cur == node2)
1402 return(-1);
1403 depth1++;
1404 }
1405 /*
1406 * Distinct document (or distinct entities :-( ) case.
1407 */
1408 if (root != cur) {
1409 return(-2);
1410 }
1411 /*
1412 * get the nearest common ancestor.
1413 */
1414 while (depth1 > depth2) {
1415 depth1--;
1416 node1 = node1->parent;
1417 }
1418 while (depth2 > depth1) {
1419 depth2--;
1420 node2 = node2->parent;
1421 }
1422 while (node1->parent != node2->parent) {
1423 node1 = node1->parent;
1424 node2 = node2->parent;
1425 /* should not happen but just in case ... */
1426 if ((node1 == NULL) || (node2 == NULL))
1427 return(-2);
1428 }
1429 /*
1430 * Find who's first.
1431 */
1432 if (node1 == node2->next)
1433 return(-1);
1434 for (cur = node1->next;cur != NULL;cur = cur->next)
1435 if (cur == node2)
1436 return(1);
1437 return(-1); /* assume there is no sibling list corruption */
1438}
1439
1440/**
1441 * xmlXPathNodeSetSort:
1442 * @set: the node set
1443 *
1444 * Sort the node set in document order
1445 */
1446void
1447xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001448 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001449 xmlNodePtr tmp;
1450
1451 if (set == NULL)
1452 return;
1453
1454 /* Use Shell's sort to sort the node-set */
1455 len = set->nodeNr;
1456 for (incr = len / 2; incr > 0; incr /= 2) {
1457 for (i = incr; i < len; i++) {
1458 j = i - incr;
1459 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001460 if (xmlXPathCmpNodes(set->nodeTab[j],
1461 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001462 tmp = set->nodeTab[j];
1463 set->nodeTab[j] = set->nodeTab[j + incr];
1464 set->nodeTab[j + incr] = tmp;
1465 j -= incr;
1466 } else
1467 break;
1468 }
1469 }
1470 }
1471}
1472
1473#define XML_NODESET_DEFAULT 10
1474/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001475 * xmlXPathNodeSetDupNs:
1476 * @node: the parent node of the namespace XPath node
1477 * @ns: the libxml namespace declaration node.
1478 *
1479 * Namespace node in libxml don't match the XPath semantic. In a node set
1480 * the namespace nodes are duplicated and the next pointer is set to the
1481 * parent node in the XPath semantic.
1482 *
1483 * Returns the newly created object.
1484 */
1485static xmlNodePtr
1486xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
1487 xmlNsPtr cur;
1488
1489 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1490 return(NULL);
1491 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
1492 return((xmlNodePtr) ns);
1493
1494 /*
1495 * Allocate a new Namespace and fill the fields.
1496 */
1497 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1498 if (cur == NULL) {
1499 xmlGenericError(xmlGenericErrorContext,
1500 "xmlXPathNodeSetDupNs : malloc failed\n");
1501 return(NULL);
1502 }
1503 memset(cur, 0, sizeof(xmlNs));
1504 cur->type = XML_NAMESPACE_DECL;
1505 if (ns->href != NULL)
1506 cur->href = xmlStrdup(ns->href);
1507 if (ns->prefix != NULL)
1508 cur->prefix = xmlStrdup(ns->prefix);
1509 cur->next = (xmlNsPtr) node;
1510 return((xmlNodePtr) cur);
1511}
1512
1513/**
1514 * xmlXPathNodeSetFreeNs:
1515 * @ns: the XPath namespace node found in a nodeset.
1516 *
1517 * Namespace node in libxml don't match the XPath semantic. In a node set
1518 * the namespace nodes are duplicated and the next pointer is set to the
1519 * parent node in the XPath semantic. Check if such a node need to be freed
1520 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001521void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001522xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
1523 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1524 return;
1525
1526 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
1527 if (ns->href != NULL)
1528 xmlFree((xmlChar *)ns->href);
1529 if (ns->prefix != NULL)
1530 xmlFree((xmlChar *)ns->prefix);
1531 xmlFree(ns);
1532 }
1533}
1534
1535/**
Owen Taylor3473f882001-02-23 17:55:21 +00001536 * xmlXPathNodeSetCreate:
1537 * @val: an initial xmlNodePtr, or NULL
1538 *
1539 * Create a new xmlNodeSetPtr of type double and of value @val
1540 *
1541 * Returns the newly created object.
1542 */
1543xmlNodeSetPtr
1544xmlXPathNodeSetCreate(xmlNodePtr val) {
1545 xmlNodeSetPtr ret;
1546
1547 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1548 if (ret == NULL) {
1549 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001550 "xmlXPathNodeSetCreate: out of memory\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001551 return(NULL);
1552 }
1553 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1554 if (val != NULL) {
1555 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1556 sizeof(xmlNodePtr));
1557 if (ret->nodeTab == NULL) {
1558 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001559 "xmlXPathNodeSetCreate: out of memory\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001560 return(NULL);
1561 }
1562 memset(ret->nodeTab, 0 ,
1563 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1564 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001565 if (val->type == XML_NAMESPACE_DECL) {
1566 xmlNsPtr ns = (xmlNsPtr) val;
1567
1568 ret->nodeTab[ret->nodeNr++] =
1569 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1570 } else
1571 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001572 }
1573 return(ret);
1574}
1575
1576/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001577 * xmlXPathNodeSetContains:
1578 * @cur: the node-set
1579 * @val: the node
1580 *
1581 * checks whether @cur contains @val
1582 *
1583 * Returns true (1) if @cur contains @val, false (0) otherwise
1584 */
1585int
1586xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1587 int i;
1588
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001589 if (val->type == XML_NAMESPACE_DECL) {
1590 for (i = 0; i < cur->nodeNr; i++) {
1591 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1592 xmlNsPtr ns1, ns2;
1593
1594 ns1 = (xmlNsPtr) val;
1595 ns2 = (xmlNsPtr) cur->nodeTab[i];
1596 if (ns1 == ns2)
1597 return(1);
1598 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
1599 (xmlStrEqual(ns1->prefix, ns2->prefix)))
1600 return(1);
1601 }
1602 }
1603 } else {
1604 for (i = 0; i < cur->nodeNr; i++) {
1605 if (cur->nodeTab[i] == val)
1606 return(1);
1607 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001608 }
1609 return(0);
1610}
1611
1612/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001613 * xmlXPathNodeSetAddNs:
1614 * @cur: the initial node set
1615 * @node: the hosting node
1616 * @ns: a the namespace node
1617 *
1618 * add a new namespace node to an existing NodeSet
1619 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00001620void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001621xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
1622 int i;
1623
1624 if ((ns == NULL) || (node == NULL) || (ns->type != XML_NAMESPACE_DECL) ||
1625 (node->type != XML_ELEMENT_NODE))
1626 return;
1627
1628 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1629 /*
1630 * check against doublons
1631 */
1632 for (i = 0;i < cur->nodeNr;i++) {
1633 if ((cur->nodeTab[i] != NULL) &&
1634 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00001635 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001636 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
1637 return;
1638 }
1639
1640 /*
1641 * grow the nodeTab if needed
1642 */
1643 if (cur->nodeMax == 0) {
1644 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1645 sizeof(xmlNodePtr));
1646 if (cur->nodeTab == NULL) {
1647 xmlGenericError(xmlGenericErrorContext,
1648 "xmlXPathNodeSetAdd: out of memory\n");
1649 return;
1650 }
1651 memset(cur->nodeTab, 0 ,
1652 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1653 cur->nodeMax = XML_NODESET_DEFAULT;
1654 } else if (cur->nodeNr == cur->nodeMax) {
1655 xmlNodePtr *temp;
1656
1657 cur->nodeMax *= 2;
1658 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1659 sizeof(xmlNodePtr));
1660 if (temp == NULL) {
1661 xmlGenericError(xmlGenericErrorContext,
1662 "xmlXPathNodeSetAdd: out of memory\n");
1663 return;
1664 }
1665 cur->nodeTab = temp;
1666 }
1667 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
1668}
1669
1670/**
Owen Taylor3473f882001-02-23 17:55:21 +00001671 * xmlXPathNodeSetAdd:
1672 * @cur: the initial node set
1673 * @val: a new xmlNodePtr
1674 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001675 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00001676 */
1677void
1678xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1679 int i;
1680
1681 if (val == NULL) return;
1682
Daniel Veillard652d8a92003-02-04 19:28:49 +00001683 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1684 return; /* an XSLT fake node */
1685
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001686 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001687 /*
1688 * check against doublons
1689 */
1690 for (i = 0;i < cur->nodeNr;i++)
1691 if (cur->nodeTab[i] == val) return;
1692
1693 /*
1694 * grow the nodeTab if needed
1695 */
1696 if (cur->nodeMax == 0) {
1697 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1698 sizeof(xmlNodePtr));
1699 if (cur->nodeTab == NULL) {
1700 xmlGenericError(xmlGenericErrorContext,
1701 "xmlXPathNodeSetAdd: out of memory\n");
1702 return;
1703 }
1704 memset(cur->nodeTab, 0 ,
1705 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1706 cur->nodeMax = XML_NODESET_DEFAULT;
1707 } else if (cur->nodeNr == cur->nodeMax) {
1708 xmlNodePtr *temp;
1709
1710 cur->nodeMax *= 2;
1711 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1712 sizeof(xmlNodePtr));
1713 if (temp == NULL) {
1714 xmlGenericError(xmlGenericErrorContext,
1715 "xmlXPathNodeSetAdd: out of memory\n");
1716 return;
1717 }
1718 cur->nodeTab = temp;
1719 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001720 if (val->type == XML_NAMESPACE_DECL) {
1721 xmlNsPtr ns = (xmlNsPtr) val;
1722
1723 cur->nodeTab[cur->nodeNr++] =
1724 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1725 } else
1726 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001727}
1728
1729/**
1730 * xmlXPathNodeSetAddUnique:
1731 * @cur: the initial node set
1732 * @val: a new xmlNodePtr
1733 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001734 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00001735 * when we are sure the node is not already in the set.
1736 */
1737void
1738xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1739 if (val == NULL) return;
1740
Daniel Veillard652d8a92003-02-04 19:28:49 +00001741 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1742 return; /* an XSLT fake node */
1743
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001744 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001745 /*
1746 * grow the nodeTab if needed
1747 */
1748 if (cur->nodeMax == 0) {
1749 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1750 sizeof(xmlNodePtr));
1751 if (cur->nodeTab == NULL) {
1752 xmlGenericError(xmlGenericErrorContext,
1753 "xmlXPathNodeSetAddUnique: out of memory\n");
1754 return;
1755 }
1756 memset(cur->nodeTab, 0 ,
1757 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1758 cur->nodeMax = XML_NODESET_DEFAULT;
1759 } else if (cur->nodeNr == cur->nodeMax) {
1760 xmlNodePtr *temp;
1761
1762 cur->nodeMax *= 2;
1763 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1764 sizeof(xmlNodePtr));
1765 if (temp == NULL) {
1766 xmlGenericError(xmlGenericErrorContext,
1767 "xmlXPathNodeSetAddUnique: out of memory\n");
1768 return;
1769 }
1770 cur->nodeTab = temp;
1771 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001772 if (val->type == XML_NAMESPACE_DECL) {
1773 xmlNsPtr ns = (xmlNsPtr) val;
1774
1775 cur->nodeTab[cur->nodeNr++] =
1776 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1777 } else
1778 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001779}
1780
1781/**
1782 * xmlXPathNodeSetMerge:
1783 * @val1: the first NodeSet or NULL
1784 * @val2: the second NodeSet
1785 *
1786 * Merges two nodesets, all nodes from @val2 are added to @val1
1787 * if @val1 is NULL, a new set is created and copied from @val2
1788 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001789 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00001790 */
1791xmlNodeSetPtr
1792xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001793 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001794
1795 if (val2 == NULL) return(val1);
1796 if (val1 == NULL) {
1797 val1 = xmlXPathNodeSetCreate(NULL);
1798 }
1799
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001800 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001801 initNr = val1->nodeNr;
1802
1803 for (i = 0;i < val2->nodeNr;i++) {
1804 /*
1805 * check against doublons
1806 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001807 skip = 0;
1808 for (j = 0; j < initNr; j++) {
1809 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1810 skip = 1;
1811 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001812 } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) &&
1813 (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) {
1814 xmlNsPtr ns1, ns2;
1815 ns1 = (xmlNsPtr) val1->nodeTab[j];
1816 ns2 = (xmlNsPtr) val2->nodeTab[i];
1817 if ((ns1->next == ns2->next) &&
1818 (xmlStrEqual(ns1->prefix, ns2->prefix))) {
1819 skip = 1;
1820 break;
1821 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001822 }
1823 }
1824 if (skip)
1825 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00001826
1827 /*
1828 * grow the nodeTab if needed
1829 */
1830 if (val1->nodeMax == 0) {
1831 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1832 sizeof(xmlNodePtr));
1833 if (val1->nodeTab == NULL) {
1834 xmlGenericError(xmlGenericErrorContext,
1835 "xmlXPathNodeSetMerge: out of memory\n");
1836 return(NULL);
1837 }
1838 memset(val1->nodeTab, 0 ,
1839 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1840 val1->nodeMax = XML_NODESET_DEFAULT;
1841 } else if (val1->nodeNr == val1->nodeMax) {
1842 xmlNodePtr *temp;
1843
1844 val1->nodeMax *= 2;
1845 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1846 sizeof(xmlNodePtr));
1847 if (temp == NULL) {
1848 xmlGenericError(xmlGenericErrorContext,
1849 "xmlXPathNodeSetMerge: out of memory\n");
1850 return(NULL);
1851 }
1852 val1->nodeTab = temp;
1853 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001854 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1855 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1856
1857 val1->nodeTab[val1->nodeNr++] =
1858 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1859 } else
1860 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00001861 }
1862
1863 return(val1);
1864}
1865
1866/**
Daniel Veillard75be0132002-03-13 10:03:35 +00001867 * xmlXPathNodeSetMergeUnique:
1868 * @val1: the first NodeSet or NULL
1869 * @val2: the second NodeSet
1870 *
1871 * Merges two nodesets, all nodes from @val2 are added to @val1
1872 * if @val1 is NULL, a new set is created and copied from @val2
1873 *
1874 * Returns @val1 once extended or NULL in case of error.
1875 */
1876static xmlNodeSetPtr
1877xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
1878 int i, initNr;
1879
1880 if (val2 == NULL) return(val1);
1881 if (val1 == NULL) {
1882 val1 = xmlXPathNodeSetCreate(NULL);
1883 }
1884
1885 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1886 initNr = val1->nodeNr;
1887
1888 for (i = 0;i < val2->nodeNr;i++) {
1889 /*
1890 * grow the nodeTab if needed
1891 */
1892 if (val1->nodeMax == 0) {
1893 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1894 sizeof(xmlNodePtr));
1895 if (val1->nodeTab == NULL) {
1896 xmlGenericError(xmlGenericErrorContext,
1897 "xmlXPathNodeSetMerge: out of memory\n");
1898 return(NULL);
1899 }
1900 memset(val1->nodeTab, 0 ,
1901 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1902 val1->nodeMax = XML_NODESET_DEFAULT;
1903 } else if (val1->nodeNr == val1->nodeMax) {
1904 xmlNodePtr *temp;
1905
1906 val1->nodeMax *= 2;
1907 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1908 sizeof(xmlNodePtr));
1909 if (temp == NULL) {
1910 xmlGenericError(xmlGenericErrorContext,
1911 "xmlXPathNodeSetMerge: out of memory\n");
1912 return(NULL);
1913 }
1914 val1->nodeTab = temp;
1915 }
1916 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1917 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1918
1919 val1->nodeTab[val1->nodeNr++] =
1920 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1921 } else
1922 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
1923 }
1924
1925 return(val1);
1926}
1927
1928/**
Owen Taylor3473f882001-02-23 17:55:21 +00001929 * xmlXPathNodeSetDel:
1930 * @cur: the initial node set
1931 * @val: an xmlNodePtr
1932 *
1933 * Removes an xmlNodePtr from an existing NodeSet
1934 */
1935void
1936xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
1937 int i;
1938
1939 if (cur == NULL) return;
1940 if (val == NULL) return;
1941
1942 /*
1943 * check against doublons
1944 */
1945 for (i = 0;i < cur->nodeNr;i++)
1946 if (cur->nodeTab[i] == val) break;
1947
1948 if (i >= cur->nodeNr) {
1949#ifdef DEBUG
1950 xmlGenericError(xmlGenericErrorContext,
1951 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
1952 val->name);
1953#endif
1954 return;
1955 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001956 if ((cur->nodeTab[i] != NULL) &&
1957 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
1958 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001959 cur->nodeNr--;
1960 for (;i < cur->nodeNr;i++)
1961 cur->nodeTab[i] = cur->nodeTab[i + 1];
1962 cur->nodeTab[cur->nodeNr] = NULL;
1963}
1964
1965/**
1966 * xmlXPathNodeSetRemove:
1967 * @cur: the initial node set
1968 * @val: the index to remove
1969 *
1970 * Removes an entry from an existing NodeSet list.
1971 */
1972void
1973xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
1974 if (cur == NULL) return;
1975 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001976 if ((cur->nodeTab[val] != NULL) &&
1977 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
1978 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00001979 cur->nodeNr--;
1980 for (;val < cur->nodeNr;val++)
1981 cur->nodeTab[val] = cur->nodeTab[val + 1];
1982 cur->nodeTab[cur->nodeNr] = NULL;
1983}
1984
1985/**
1986 * xmlXPathFreeNodeSet:
1987 * @obj: the xmlNodeSetPtr to free
1988 *
1989 * Free the NodeSet compound (not the actual nodes !).
1990 */
1991void
1992xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
1993 if (obj == NULL) return;
1994 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001995 int i;
1996
1997 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1998 for (i = 0;i < obj->nodeNr;i++)
1999 if ((obj->nodeTab[i] != NULL) &&
2000 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
2001 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002002 xmlFree(obj->nodeTab);
2003 }
Owen Taylor3473f882001-02-23 17:55:21 +00002004 xmlFree(obj);
2005}
2006
2007/**
2008 * xmlXPathFreeValueTree:
2009 * @obj: the xmlNodeSetPtr to free
2010 *
2011 * Free the NodeSet compound and the actual tree, this is different
2012 * from xmlXPathFreeNodeSet()
2013 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002014static void
Owen Taylor3473f882001-02-23 17:55:21 +00002015xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
2016 int i;
2017
2018 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002019
2020 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002021 for (i = 0;i < obj->nodeNr;i++) {
2022 if (obj->nodeTab[i] != NULL) {
2023 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2024 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
2025 } else {
2026 xmlFreeNodeList(obj->nodeTab[i]);
2027 }
2028 }
2029 }
Owen Taylor3473f882001-02-23 17:55:21 +00002030 xmlFree(obj->nodeTab);
2031 }
Owen Taylor3473f882001-02-23 17:55:21 +00002032 xmlFree(obj);
2033}
2034
2035#if defined(DEBUG) || defined(DEBUG_STEP)
2036/**
2037 * xmlGenericErrorContextNodeSet:
2038 * @output: a FILE * for the output
2039 * @obj: the xmlNodeSetPtr to free
2040 *
2041 * Quick display of a NodeSet
2042 */
2043void
2044xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
2045 int i;
2046
2047 if (output == NULL) output = xmlGenericErrorContext;
2048 if (obj == NULL) {
2049 fprintf(output, "NodeSet == NULL !\n");
2050 return;
2051 }
2052 if (obj->nodeNr == 0) {
2053 fprintf(output, "NodeSet is empty\n");
2054 return;
2055 }
2056 if (obj->nodeTab == NULL) {
2057 fprintf(output, " nodeTab == NULL !\n");
2058 return;
2059 }
2060 for (i = 0; i < obj->nodeNr; i++) {
2061 if (obj->nodeTab[i] == NULL) {
2062 fprintf(output, " NULL !\n");
2063 return;
2064 }
2065 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
2066 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
2067 fprintf(output, " /");
2068 else if (obj->nodeTab[i]->name == NULL)
2069 fprintf(output, " noname!");
2070 else fprintf(output, " %s", obj->nodeTab[i]->name);
2071 }
2072 fprintf(output, "\n");
2073}
2074#endif
2075
2076/**
2077 * xmlXPathNewNodeSet:
2078 * @val: the NodePtr value
2079 *
2080 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2081 * it with the single Node @val
2082 *
2083 * Returns the newly created object.
2084 */
2085xmlXPathObjectPtr
2086xmlXPathNewNodeSet(xmlNodePtr val) {
2087 xmlXPathObjectPtr ret;
2088
2089 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2090 if (ret == NULL) {
2091 xmlGenericError(xmlGenericErrorContext,
2092 "xmlXPathNewNodeSet: out of memory\n");
2093 return(NULL);
2094 }
2095 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2096 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00002097 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002098 ret->nodesetval = xmlXPathNodeSetCreate(val);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002099 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002100 return(ret);
2101}
2102
2103/**
2104 * xmlXPathNewValueTree:
2105 * @val: the NodePtr value
2106 *
2107 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
2108 * it with the tree root @val
2109 *
2110 * Returns the newly created object.
2111 */
2112xmlXPathObjectPtr
2113xmlXPathNewValueTree(xmlNodePtr val) {
2114 xmlXPathObjectPtr ret;
2115
2116 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2117 if (ret == NULL) {
2118 xmlGenericError(xmlGenericErrorContext,
2119 "xmlXPathNewNodeSet: out of memory\n");
2120 return(NULL);
2121 }
2122 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2123 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002124 ret->boolval = 1;
2125 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00002126 ret->nodesetval = xmlXPathNodeSetCreate(val);
2127 return(ret);
2128}
2129
2130/**
2131 * xmlXPathNewNodeSetList:
2132 * @val: an existing NodeSet
2133 *
2134 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2135 * it with the Nodeset @val
2136 *
2137 * Returns the newly created object.
2138 */
2139xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002140xmlXPathNewNodeSetList(xmlNodeSetPtr val)
2141{
Owen Taylor3473f882001-02-23 17:55:21 +00002142 xmlXPathObjectPtr ret;
2143 int i;
2144
2145 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002146 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002147 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002148 ret = xmlXPathNewNodeSet(NULL);
2149 else {
2150 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
2151 for (i = 1; i < val->nodeNr; ++i)
2152 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2153 }
Owen Taylor3473f882001-02-23 17:55:21 +00002154
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002155 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002156}
2157
2158/**
2159 * xmlXPathWrapNodeSet:
2160 * @val: the NodePtr value
2161 *
2162 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2163 *
2164 * Returns the newly created object.
2165 */
2166xmlXPathObjectPtr
2167xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2168 xmlXPathObjectPtr ret;
2169
2170 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2171 if (ret == NULL) {
2172 xmlGenericError(xmlGenericErrorContext,
2173 "xmlXPathWrapNodeSet: out of memory\n");
2174 return(NULL);
2175 }
2176 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2177 ret->type = XPATH_NODESET;
2178 ret->nodesetval = val;
2179 return(ret);
2180}
2181
2182/**
2183 * xmlXPathFreeNodeSetList:
2184 * @obj: an existing NodeSetList object
2185 *
2186 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2187 * the list contrary to xmlXPathFreeObject().
2188 */
2189void
2190xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2191 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002192 xmlFree(obj);
2193}
2194
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002195/**
2196 * xmlXPathDifference:
2197 * @nodes1: a node-set
2198 * @nodes2: a node-set
2199 *
2200 * Implements the EXSLT - Sets difference() function:
2201 * node-set set:difference (node-set, node-set)
2202 *
2203 * Returns the difference between the two node sets, or nodes1 if
2204 * nodes2 is empty
2205 */
2206xmlNodeSetPtr
2207xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2208 xmlNodeSetPtr ret;
2209 int i, l1;
2210 xmlNodePtr cur;
2211
2212 if (xmlXPathNodeSetIsEmpty(nodes2))
2213 return(nodes1);
2214
2215 ret = xmlXPathNodeSetCreate(NULL);
2216 if (xmlXPathNodeSetIsEmpty(nodes1))
2217 return(ret);
2218
2219 l1 = xmlXPathNodeSetGetLength(nodes1);
2220
2221 for (i = 0; i < l1; i++) {
2222 cur = xmlXPathNodeSetItem(nodes1, i);
2223 if (!xmlXPathNodeSetContains(nodes2, cur))
2224 xmlXPathNodeSetAddUnique(ret, cur);
2225 }
2226 return(ret);
2227}
2228
2229/**
2230 * xmlXPathIntersection:
2231 * @nodes1: a node-set
2232 * @nodes2: a node-set
2233 *
2234 * Implements the EXSLT - Sets intersection() function:
2235 * node-set set:intersection (node-set, node-set)
2236 *
2237 * Returns a node set comprising the nodes that are within both the
2238 * node sets passed as arguments
2239 */
2240xmlNodeSetPtr
2241xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2242 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2243 int i, l1;
2244 xmlNodePtr cur;
2245
2246 if (xmlXPathNodeSetIsEmpty(nodes1))
2247 return(ret);
2248 if (xmlXPathNodeSetIsEmpty(nodes2))
2249 return(ret);
2250
2251 l1 = xmlXPathNodeSetGetLength(nodes1);
2252
2253 for (i = 0; i < l1; i++) {
2254 cur = xmlXPathNodeSetItem(nodes1, i);
2255 if (xmlXPathNodeSetContains(nodes2, cur))
2256 xmlXPathNodeSetAddUnique(ret, cur);
2257 }
2258 return(ret);
2259}
2260
2261/**
2262 * xmlXPathDistinctSorted:
2263 * @nodes: a node-set, sorted by document order
2264 *
2265 * Implements the EXSLT - Sets distinct() function:
2266 * node-set set:distinct (node-set)
2267 *
2268 * Returns a subset of the nodes contained in @nodes, or @nodes if
2269 * it is empty
2270 */
2271xmlNodeSetPtr
2272xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2273 xmlNodeSetPtr ret;
2274 xmlHashTablePtr hash;
2275 int i, l;
2276 xmlChar * strval;
2277 xmlNodePtr cur;
2278
2279 if (xmlXPathNodeSetIsEmpty(nodes))
2280 return(nodes);
2281
2282 ret = xmlXPathNodeSetCreate(NULL);
2283 l = xmlXPathNodeSetGetLength(nodes);
2284 hash = xmlHashCreate (l);
2285 for (i = 0; i < l; i++) {
2286 cur = xmlXPathNodeSetItem(nodes, i);
2287 strval = xmlXPathCastNodeToString(cur);
2288 if (xmlHashLookup(hash, strval) == NULL) {
2289 xmlHashAddEntry(hash, strval, strval);
2290 xmlXPathNodeSetAddUnique(ret, cur);
2291 } else {
2292 xmlFree(strval);
2293 }
2294 }
2295 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2296 return(ret);
2297}
2298
2299/**
2300 * xmlXPathDistinct:
2301 * @nodes: a node-set
2302 *
2303 * Implements the EXSLT - Sets distinct() function:
2304 * node-set set:distinct (node-set)
2305 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2306 * is called with the sorted node-set
2307 *
2308 * Returns a subset of the nodes contained in @nodes, or @nodes if
2309 * it is empty
2310 */
2311xmlNodeSetPtr
2312xmlXPathDistinct (xmlNodeSetPtr nodes) {
2313 if (xmlXPathNodeSetIsEmpty(nodes))
2314 return(nodes);
2315
2316 xmlXPathNodeSetSort(nodes);
2317 return(xmlXPathDistinctSorted(nodes));
2318}
2319
2320/**
2321 * xmlXPathHasSameNodes:
2322 * @nodes1: a node-set
2323 * @nodes2: a node-set
2324 *
2325 * Implements the EXSLT - Sets has-same-nodes function:
2326 * boolean set:has-same-node(node-set, node-set)
2327 *
2328 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2329 * otherwise
2330 */
2331int
2332xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2333 int i, l;
2334 xmlNodePtr cur;
2335
2336 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2337 xmlXPathNodeSetIsEmpty(nodes2))
2338 return(0);
2339
2340 l = xmlXPathNodeSetGetLength(nodes1);
2341 for (i = 0; i < l; i++) {
2342 cur = xmlXPathNodeSetItem(nodes1, i);
2343 if (xmlXPathNodeSetContains(nodes2, cur))
2344 return(1);
2345 }
2346 return(0);
2347}
2348
2349/**
2350 * xmlXPathNodeLeadingSorted:
2351 * @nodes: a node-set, sorted by document order
2352 * @node: a node
2353 *
2354 * Implements the EXSLT - Sets leading() function:
2355 * node-set set:leading (node-set, node-set)
2356 *
2357 * Returns the nodes in @nodes that precede @node in document order,
2358 * @nodes if @node is NULL or an empty node-set if @nodes
2359 * doesn't contain @node
2360 */
2361xmlNodeSetPtr
2362xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2363 int i, l;
2364 xmlNodePtr cur;
2365 xmlNodeSetPtr ret;
2366
2367 if (node == NULL)
2368 return(nodes);
2369
2370 ret = xmlXPathNodeSetCreate(NULL);
2371 if (xmlXPathNodeSetIsEmpty(nodes) ||
2372 (!xmlXPathNodeSetContains(nodes, node)))
2373 return(ret);
2374
2375 l = xmlXPathNodeSetGetLength(nodes);
2376 for (i = 0; i < l; i++) {
2377 cur = xmlXPathNodeSetItem(nodes, i);
2378 if (cur == node)
2379 break;
2380 xmlXPathNodeSetAddUnique(ret, cur);
2381 }
2382 return(ret);
2383}
2384
2385/**
2386 * xmlXPathNodeLeading:
2387 * @nodes: a node-set
2388 * @node: a node
2389 *
2390 * Implements the EXSLT - Sets leading() function:
2391 * node-set set:leading (node-set, node-set)
2392 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2393 * is called.
2394 *
2395 * Returns the nodes in @nodes that precede @node in document order,
2396 * @nodes if @node is NULL or an empty node-set if @nodes
2397 * doesn't contain @node
2398 */
2399xmlNodeSetPtr
2400xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2401 xmlXPathNodeSetSort(nodes);
2402 return(xmlXPathNodeLeadingSorted(nodes, node));
2403}
2404
2405/**
2406 * xmlXPathLeadingSorted:
2407 * @nodes1: a node-set, sorted by document order
2408 * @nodes2: a node-set, sorted by document order
2409 *
2410 * Implements the EXSLT - Sets leading() function:
2411 * node-set set:leading (node-set, node-set)
2412 *
2413 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2414 * in document order, @nodes1 if @nodes2 is NULL or empty or
2415 * an empty node-set if @nodes1 doesn't contain @nodes2
2416 */
2417xmlNodeSetPtr
2418xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2419 if (xmlXPathNodeSetIsEmpty(nodes2))
2420 return(nodes1);
2421 return(xmlXPathNodeLeadingSorted(nodes1,
2422 xmlXPathNodeSetItem(nodes2, 1)));
2423}
2424
2425/**
2426 * xmlXPathLeading:
2427 * @nodes1: a node-set
2428 * @nodes2: a node-set
2429 *
2430 * Implements the EXSLT - Sets leading() function:
2431 * node-set set:leading (node-set, node-set)
2432 * @nodes1 and @nodes2 are sorted by document order, then
2433 * #exslSetsLeadingSorted is called.
2434 *
2435 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2436 * in document order, @nodes1 if @nodes2 is NULL or empty or
2437 * an empty node-set if @nodes1 doesn't contain @nodes2
2438 */
2439xmlNodeSetPtr
2440xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2441 if (xmlXPathNodeSetIsEmpty(nodes2))
2442 return(nodes1);
2443 if (xmlXPathNodeSetIsEmpty(nodes1))
2444 return(xmlXPathNodeSetCreate(NULL));
2445 xmlXPathNodeSetSort(nodes1);
2446 xmlXPathNodeSetSort(nodes2);
2447 return(xmlXPathNodeLeadingSorted(nodes1,
2448 xmlXPathNodeSetItem(nodes2, 1)));
2449}
2450
2451/**
2452 * xmlXPathNodeTrailingSorted:
2453 * @nodes: a node-set, sorted by document order
2454 * @node: a node
2455 *
2456 * Implements the EXSLT - Sets trailing() function:
2457 * node-set set:trailing (node-set, node-set)
2458 *
2459 * Returns the nodes in @nodes that follow @node in document order,
2460 * @nodes if @node is NULL or an empty node-set if @nodes
2461 * doesn't contain @node
2462 */
2463xmlNodeSetPtr
2464xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2465 int i, l;
2466 xmlNodePtr cur;
2467 xmlNodeSetPtr ret;
2468
2469 if (node == NULL)
2470 return(nodes);
2471
2472 ret = xmlXPathNodeSetCreate(NULL);
2473 if (xmlXPathNodeSetIsEmpty(nodes) ||
2474 (!xmlXPathNodeSetContains(nodes, node)))
2475 return(ret);
2476
2477 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002478 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002479 cur = xmlXPathNodeSetItem(nodes, i);
2480 if (cur == node)
2481 break;
2482 xmlXPathNodeSetAddUnique(ret, cur);
2483 }
2484 return(ret);
2485}
2486
2487/**
2488 * xmlXPathNodeTrailing:
2489 * @nodes: a node-set
2490 * @node: a node
2491 *
2492 * Implements the EXSLT - Sets trailing() function:
2493 * node-set set:trailing (node-set, node-set)
2494 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2495 * is called.
2496 *
2497 * Returns the nodes in @nodes that follow @node in document order,
2498 * @nodes if @node is NULL or an empty node-set if @nodes
2499 * doesn't contain @node
2500 */
2501xmlNodeSetPtr
2502xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2503 xmlXPathNodeSetSort(nodes);
2504 return(xmlXPathNodeTrailingSorted(nodes, node));
2505}
2506
2507/**
2508 * xmlXPathTrailingSorted:
2509 * @nodes1: a node-set, sorted by document order
2510 * @nodes2: a node-set, sorted by document order
2511 *
2512 * Implements the EXSLT - Sets trailing() function:
2513 * node-set set:trailing (node-set, node-set)
2514 *
2515 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2516 * in document order, @nodes1 if @nodes2 is NULL or empty or
2517 * an empty node-set if @nodes1 doesn't contain @nodes2
2518 */
2519xmlNodeSetPtr
2520xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2521 if (xmlXPathNodeSetIsEmpty(nodes2))
2522 return(nodes1);
2523 return(xmlXPathNodeTrailingSorted(nodes1,
2524 xmlXPathNodeSetItem(nodes2, 0)));
2525}
2526
2527/**
2528 * xmlXPathTrailing:
2529 * @nodes1: a node-set
2530 * @nodes2: a node-set
2531 *
2532 * Implements the EXSLT - Sets trailing() function:
2533 * node-set set:trailing (node-set, node-set)
2534 * @nodes1 and @nodes2 are sorted by document order, then
2535 * #xmlXPathTrailingSorted is called.
2536 *
2537 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2538 * in document order, @nodes1 if @nodes2 is NULL or empty or
2539 * an empty node-set if @nodes1 doesn't contain @nodes2
2540 */
2541xmlNodeSetPtr
2542xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2543 if (xmlXPathNodeSetIsEmpty(nodes2))
2544 return(nodes1);
2545 if (xmlXPathNodeSetIsEmpty(nodes1))
2546 return(xmlXPathNodeSetCreate(NULL));
2547 xmlXPathNodeSetSort(nodes1);
2548 xmlXPathNodeSetSort(nodes2);
2549 return(xmlXPathNodeTrailingSorted(nodes1,
2550 xmlXPathNodeSetItem(nodes2, 0)));
2551}
2552
Owen Taylor3473f882001-02-23 17:55:21 +00002553/************************************************************************
2554 * *
2555 * Routines to handle extra functions *
2556 * *
2557 ************************************************************************/
2558
2559/**
2560 * xmlXPathRegisterFunc:
2561 * @ctxt: the XPath context
2562 * @name: the function name
2563 * @f: the function implementation or NULL
2564 *
2565 * Register a new function. If @f is NULL it unregisters the function
2566 *
2567 * Returns 0 in case of success, -1 in case of error
2568 */
2569int
2570xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2571 xmlXPathFunction f) {
2572 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2573}
2574
2575/**
2576 * xmlXPathRegisterFuncNS:
2577 * @ctxt: the XPath context
2578 * @name: the function name
2579 * @ns_uri: the function namespace URI
2580 * @f: the function implementation or NULL
2581 *
2582 * Register a new function. If @f is NULL it unregisters the function
2583 *
2584 * Returns 0 in case of success, -1 in case of error
2585 */
2586int
2587xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2588 const xmlChar *ns_uri, xmlXPathFunction f) {
2589 if (ctxt == NULL)
2590 return(-1);
2591 if (name == NULL)
2592 return(-1);
2593
2594 if (ctxt->funcHash == NULL)
2595 ctxt->funcHash = xmlHashCreate(0);
2596 if (ctxt->funcHash == NULL)
2597 return(-1);
2598 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2599}
2600
2601/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002602 * xmlXPathRegisterFuncLookup:
2603 * @ctxt: the XPath context
2604 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002605 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00002606 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002607 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00002608 */
2609void
2610xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2611 xmlXPathFuncLookupFunc f,
2612 void *funcCtxt) {
2613 if (ctxt == NULL)
2614 return;
2615 ctxt->funcLookupFunc = (void *) f;
2616 ctxt->funcLookupData = funcCtxt;
2617}
2618
2619/**
Owen Taylor3473f882001-02-23 17:55:21 +00002620 * xmlXPathFunctionLookup:
2621 * @ctxt: the XPath context
2622 * @name: the function name
2623 *
2624 * Search in the Function array of the context for the given
2625 * function.
2626 *
2627 * Returns the xmlXPathFunction or NULL if not found
2628 */
2629xmlXPathFunction
2630xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002631 if (ctxt == NULL)
2632 return (NULL);
2633
2634 if (ctxt->funcLookupFunc != NULL) {
2635 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002636 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002637
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002638 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002639 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002640 if (ret != NULL)
2641 return(ret);
2642 }
Owen Taylor3473f882001-02-23 17:55:21 +00002643 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2644}
2645
2646/**
2647 * xmlXPathFunctionLookupNS:
2648 * @ctxt: the XPath context
2649 * @name: the function name
2650 * @ns_uri: the function namespace URI
2651 *
2652 * Search in the Function array of the context for the given
2653 * function.
2654 *
2655 * Returns the xmlXPathFunction or NULL if not found
2656 */
2657xmlXPathFunction
2658xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2659 const xmlChar *ns_uri) {
2660 if (ctxt == NULL)
2661 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002662 if (name == NULL)
2663 return(NULL);
2664
Thomas Broyerba4ad322001-07-26 16:55:21 +00002665 if (ctxt->funcLookupFunc != NULL) {
2666 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002667 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002668
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002669 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002670 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002671 if (ret != NULL)
2672 return(ret);
2673 }
2674
2675 if (ctxt->funcHash == NULL)
2676 return(NULL);
2677
Owen Taylor3473f882001-02-23 17:55:21 +00002678 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2679}
2680
2681/**
2682 * xmlXPathRegisteredFuncsCleanup:
2683 * @ctxt: the XPath context
2684 *
2685 * Cleanup the XPath context data associated to registered functions
2686 */
2687void
2688xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2689 if (ctxt == NULL)
2690 return;
2691
2692 xmlHashFree(ctxt->funcHash, NULL);
2693 ctxt->funcHash = NULL;
2694}
2695
2696/************************************************************************
2697 * *
2698 * Routines to handle Variable *
2699 * *
2700 ************************************************************************/
2701
2702/**
2703 * xmlXPathRegisterVariable:
2704 * @ctxt: the XPath context
2705 * @name: the variable name
2706 * @value: the variable value or NULL
2707 *
2708 * Register a new variable value. If @value is NULL it unregisters
2709 * the variable
2710 *
2711 * Returns 0 in case of success, -1 in case of error
2712 */
2713int
2714xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2715 xmlXPathObjectPtr value) {
2716 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2717}
2718
2719/**
2720 * xmlXPathRegisterVariableNS:
2721 * @ctxt: the XPath context
2722 * @name: the variable name
2723 * @ns_uri: the variable namespace URI
2724 * @value: the variable value or NULL
2725 *
2726 * Register a new variable value. If @value is NULL it unregisters
2727 * the variable
2728 *
2729 * Returns 0 in case of success, -1 in case of error
2730 */
2731int
2732xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2733 const xmlChar *ns_uri,
2734 xmlXPathObjectPtr value) {
2735 if (ctxt == NULL)
2736 return(-1);
2737 if (name == NULL)
2738 return(-1);
2739
2740 if (ctxt->varHash == NULL)
2741 ctxt->varHash = xmlHashCreate(0);
2742 if (ctxt->varHash == NULL)
2743 return(-1);
2744 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2745 (void *) value,
2746 (xmlHashDeallocator)xmlXPathFreeObject));
2747}
2748
2749/**
2750 * xmlXPathRegisterVariableLookup:
2751 * @ctxt: the XPath context
2752 * @f: the lookup function
2753 * @data: the lookup data
2754 *
2755 * register an external mechanism to do variable lookup
2756 */
2757void
2758xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2759 xmlXPathVariableLookupFunc f, void *data) {
2760 if (ctxt == NULL)
2761 return;
2762 ctxt->varLookupFunc = (void *) f;
2763 ctxt->varLookupData = data;
2764}
2765
2766/**
2767 * xmlXPathVariableLookup:
2768 * @ctxt: the XPath context
2769 * @name: the variable name
2770 *
2771 * Search in the Variable array of the context for the given
2772 * variable value.
2773 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002774 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002775 */
2776xmlXPathObjectPtr
2777xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2778 if (ctxt == NULL)
2779 return(NULL);
2780
2781 if (ctxt->varLookupFunc != NULL) {
2782 xmlXPathObjectPtr ret;
2783
2784 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2785 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00002786 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002787 }
2788 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
2789}
2790
2791/**
2792 * xmlXPathVariableLookupNS:
2793 * @ctxt: the XPath context
2794 * @name: the variable name
2795 * @ns_uri: the variable namespace URI
2796 *
2797 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00002798 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00002799 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002800 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002801 */
2802xmlXPathObjectPtr
2803xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2804 const xmlChar *ns_uri) {
2805 if (ctxt == NULL)
2806 return(NULL);
2807
2808 if (ctxt->varLookupFunc != NULL) {
2809 xmlXPathObjectPtr ret;
2810
2811 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2812 (ctxt->varLookupData, name, ns_uri);
2813 if (ret != NULL) return(ret);
2814 }
2815
2816 if (ctxt->varHash == NULL)
2817 return(NULL);
2818 if (name == NULL)
2819 return(NULL);
2820
Daniel Veillard8c357d52001-07-03 23:43:33 +00002821 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
2822 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00002823}
2824
2825/**
2826 * xmlXPathRegisteredVariablesCleanup:
2827 * @ctxt: the XPath context
2828 *
2829 * Cleanup the XPath context data associated to registered variables
2830 */
2831void
2832xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
2833 if (ctxt == NULL)
2834 return;
2835
Daniel Veillard76d66f42001-05-16 21:05:17 +00002836 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00002837 ctxt->varHash = NULL;
2838}
2839
2840/**
2841 * xmlXPathRegisterNs:
2842 * @ctxt: the XPath context
2843 * @prefix: the namespace prefix
2844 * @ns_uri: the namespace name
2845 *
2846 * Register a new namespace. If @ns_uri is NULL it unregisters
2847 * the namespace
2848 *
2849 * Returns 0 in case of success, -1 in case of error
2850 */
2851int
2852xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
2853 const xmlChar *ns_uri) {
2854 if (ctxt == NULL)
2855 return(-1);
2856 if (prefix == NULL)
2857 return(-1);
2858
2859 if (ctxt->nsHash == NULL)
2860 ctxt->nsHash = xmlHashCreate(10);
2861 if (ctxt->nsHash == NULL)
2862 return(-1);
Daniel Veillard42766c02002-08-22 20:52:17 +00002863 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00002864 (xmlHashDeallocator)xmlFree));
2865}
2866
2867/**
2868 * xmlXPathNsLookup:
2869 * @ctxt: the XPath context
2870 * @prefix: the namespace prefix value
2871 *
2872 * Search in the namespace declaration array of the context for the given
2873 * namespace name associated to the given prefix
2874 *
2875 * Returns the value or NULL if not found
2876 */
2877const xmlChar *
2878xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
2879 if (ctxt == NULL)
2880 return(NULL);
2881 if (prefix == NULL)
2882 return(NULL);
2883
2884#ifdef XML_XML_NAMESPACE
2885 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
2886 return(XML_XML_NAMESPACE);
2887#endif
2888
Daniel Veillardc8f620b2001-04-30 20:31:33 +00002889 if (ctxt->namespaces != NULL) {
2890 int i;
2891
2892 for (i = 0;i < ctxt->nsNr;i++) {
2893 if ((ctxt->namespaces[i] != NULL) &&
2894 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
2895 return(ctxt->namespaces[i]->href);
2896 }
2897 }
Owen Taylor3473f882001-02-23 17:55:21 +00002898
2899 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
2900}
2901
2902/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002903 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00002904 * @ctxt: the XPath context
2905 *
2906 * Cleanup the XPath context data associated to registered variables
2907 */
2908void
2909xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
2910 if (ctxt == NULL)
2911 return;
2912
Daniel Veillard42766c02002-08-22 20:52:17 +00002913 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00002914 ctxt->nsHash = NULL;
2915}
2916
2917/************************************************************************
2918 * *
2919 * Routines to handle Values *
2920 * *
2921 ************************************************************************/
2922
2923/* Allocations are terrible, one need to optimize all this !!! */
2924
2925/**
2926 * xmlXPathNewFloat:
2927 * @val: the double value
2928 *
2929 * Create a new xmlXPathObjectPtr of type double and of value @val
2930 *
2931 * Returns the newly created object.
2932 */
2933xmlXPathObjectPtr
2934xmlXPathNewFloat(double val) {
2935 xmlXPathObjectPtr ret;
2936
2937 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2938 if (ret == NULL) {
2939 xmlGenericError(xmlGenericErrorContext,
2940 "xmlXPathNewFloat: out of memory\n");
2941 return(NULL);
2942 }
2943 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2944 ret->type = XPATH_NUMBER;
2945 ret->floatval = val;
2946 return(ret);
2947}
2948
2949/**
2950 * xmlXPathNewBoolean:
2951 * @val: the boolean value
2952 *
2953 * Create a new xmlXPathObjectPtr of type boolean and of value @val
2954 *
2955 * Returns the newly created object.
2956 */
2957xmlXPathObjectPtr
2958xmlXPathNewBoolean(int val) {
2959 xmlXPathObjectPtr ret;
2960
2961 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2962 if (ret == NULL) {
2963 xmlGenericError(xmlGenericErrorContext,
2964 "xmlXPathNewBoolean: out of memory\n");
2965 return(NULL);
2966 }
2967 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2968 ret->type = XPATH_BOOLEAN;
2969 ret->boolval = (val != 0);
2970 return(ret);
2971}
2972
2973/**
2974 * xmlXPathNewString:
2975 * @val: the xmlChar * value
2976 *
2977 * Create a new xmlXPathObjectPtr of type string and of value @val
2978 *
2979 * Returns the newly created object.
2980 */
2981xmlXPathObjectPtr
2982xmlXPathNewString(const xmlChar *val) {
2983 xmlXPathObjectPtr ret;
2984
2985 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2986 if (ret == NULL) {
2987 xmlGenericError(xmlGenericErrorContext,
2988 "xmlXPathNewString: out of memory\n");
2989 return(NULL);
2990 }
2991 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2992 ret->type = XPATH_STRING;
2993 if (val != NULL)
2994 ret->stringval = xmlStrdup(val);
2995 else
2996 ret->stringval = xmlStrdup((const xmlChar *)"");
2997 return(ret);
2998}
2999
3000/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003001 * xmlXPathWrapString:
3002 * @val: the xmlChar * value
3003 *
3004 * Wraps the @val string into an XPath object.
3005 *
3006 * Returns the newly created object.
3007 */
3008xmlXPathObjectPtr
3009xmlXPathWrapString (xmlChar *val) {
3010 xmlXPathObjectPtr ret;
3011
3012 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3013 if (ret == NULL) {
3014 xmlGenericError(xmlGenericErrorContext,
3015 "xmlXPathWrapString: out of memory\n");
3016 return(NULL);
3017 }
3018 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3019 ret->type = XPATH_STRING;
3020 ret->stringval = val;
3021 return(ret);
3022}
3023
3024/**
Owen Taylor3473f882001-02-23 17:55:21 +00003025 * xmlXPathNewCString:
3026 * @val: the char * value
3027 *
3028 * Create a new xmlXPathObjectPtr of type string and of value @val
3029 *
3030 * Returns the newly created object.
3031 */
3032xmlXPathObjectPtr
3033xmlXPathNewCString(const char *val) {
3034 xmlXPathObjectPtr ret;
3035
3036 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3037 if (ret == NULL) {
3038 xmlGenericError(xmlGenericErrorContext,
3039 "xmlXPathNewCString: out of memory\n");
3040 return(NULL);
3041 }
3042 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3043 ret->type = XPATH_STRING;
3044 ret->stringval = xmlStrdup(BAD_CAST val);
3045 return(ret);
3046}
3047
3048/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003049 * xmlXPathWrapCString:
3050 * @val: the char * value
3051 *
3052 * Wraps a string into an XPath object.
3053 *
3054 * Returns the newly created object.
3055 */
3056xmlXPathObjectPtr
3057xmlXPathWrapCString (char * val) {
3058 return(xmlXPathWrapString((xmlChar *)(val)));
3059}
3060
3061/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003062 * xmlXPathWrapExternal:
3063 * @val: the user data
3064 *
3065 * Wraps the @val data into an XPath object.
3066 *
3067 * Returns the newly created object.
3068 */
3069xmlXPathObjectPtr
3070xmlXPathWrapExternal (void *val) {
3071 xmlXPathObjectPtr ret;
3072
3073 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3074 if (ret == NULL) {
3075 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003076 "xmlXPathWrapExternal: out of memory\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003077 return(NULL);
3078 }
3079 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3080 ret->type = XPATH_USERS;
3081 ret->user = val;
3082 return(ret);
3083}
3084
3085/**
Owen Taylor3473f882001-02-23 17:55:21 +00003086 * xmlXPathObjectCopy:
3087 * @val: the original object
3088 *
3089 * allocate a new copy of a given object
3090 *
3091 * Returns the newly created object.
3092 */
3093xmlXPathObjectPtr
3094xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3095 xmlXPathObjectPtr ret;
3096
3097 if (val == NULL)
3098 return(NULL);
3099
3100 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3101 if (ret == NULL) {
3102 xmlGenericError(xmlGenericErrorContext,
3103 "xmlXPathObjectCopy: out of memory\n");
3104 return(NULL);
3105 }
3106 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3107 switch (val->type) {
3108 case XPATH_BOOLEAN:
3109 case XPATH_NUMBER:
3110 case XPATH_POINT:
3111 case XPATH_RANGE:
3112 break;
3113 case XPATH_STRING:
3114 ret->stringval = xmlStrdup(val->stringval);
3115 break;
3116 case XPATH_XSLT_TREE:
3117 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003118 (val->nodesetval->nodeTab != NULL)) {
3119 ret->boolval = 1;
Daniel Veillard6ab38382001-10-06 13:08:27 +00003120 ret->user = xmlDocCopyNode(val->nodesetval->nodeTab[0],
3121 val->nodesetval->nodeTab[0]->doc, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003122 ret->nodesetval = xmlXPathNodeSetCreate(
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003123 (xmlNodePtr) ret->user);
3124 } else
Owen Taylor3473f882001-02-23 17:55:21 +00003125 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003126 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00003127 break;
3128 case XPATH_NODESET:
3129 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003130 /* Do not deallocate the copied tree value */
3131 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003132 break;
3133 case XPATH_LOCATIONSET:
3134#ifdef LIBXML_XPTR_ENABLED
3135 {
3136 xmlLocationSetPtr loc = val->user;
3137 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3138 break;
3139 }
3140#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00003141 case XPATH_USERS:
3142 ret->user = val->user;
3143 break;
3144 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00003145 xmlGenericError(xmlGenericErrorContext,
3146 "xmlXPathObjectCopy: unsupported type %d\n",
3147 val->type);
3148 break;
3149 }
3150 return(ret);
3151}
3152
3153/**
3154 * xmlXPathFreeObject:
3155 * @obj: the object to free
3156 *
3157 * Free up an xmlXPathObjectPtr object.
3158 */
3159void
3160xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3161 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003162 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00003163 if (obj->boolval) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003164 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003165 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00003166 xmlFreeNodeList((xmlNodePtr) obj->user);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003167 } else if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00003168 xmlXPathFreeValueTree(obj->nodesetval);
3169 } else {
3170 if (obj->nodesetval != NULL)
3171 xmlXPathFreeNodeSet(obj->nodesetval);
3172 }
Owen Taylor3473f882001-02-23 17:55:21 +00003173#ifdef LIBXML_XPTR_ENABLED
3174 } else if (obj->type == XPATH_LOCATIONSET) {
3175 if (obj->user != NULL)
3176 xmlXPtrFreeLocationSet(obj->user);
3177#endif
3178 } else if (obj->type == XPATH_STRING) {
3179 if (obj->stringval != NULL)
3180 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00003181 }
3182
Owen Taylor3473f882001-02-23 17:55:21 +00003183 xmlFree(obj);
3184}
3185
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003186
3187/************************************************************************
3188 * *
3189 * Type Casting Routines *
3190 * *
3191 ************************************************************************/
3192
3193/**
3194 * xmlXPathCastBooleanToString:
3195 * @val: a boolean
3196 *
3197 * Converts a boolean to its string value.
3198 *
3199 * Returns a newly allocated string.
3200 */
3201xmlChar *
3202xmlXPathCastBooleanToString (int val) {
3203 xmlChar *ret;
3204 if (val)
3205 ret = xmlStrdup((const xmlChar *) "true");
3206 else
3207 ret = xmlStrdup((const xmlChar *) "false");
3208 return(ret);
3209}
3210
3211/**
3212 * xmlXPathCastNumberToString:
3213 * @val: a number
3214 *
3215 * Converts a number to its string value.
3216 *
3217 * Returns a newly allocated string.
3218 */
3219xmlChar *
3220xmlXPathCastNumberToString (double val) {
3221 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00003222 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003223 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003224 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003225 break;
3226 case -1:
3227 ret = xmlStrdup((const xmlChar *) "-Infinity");
3228 break;
3229 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003230 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003231 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00003232 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
3233 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003234 } else {
3235 /* could be improved */
3236 char buf[100];
3237 xmlXPathFormatNumber(val, buf, 100);
3238 ret = xmlStrdup((const xmlChar *) buf);
3239 }
3240 }
3241 return(ret);
3242}
3243
3244/**
3245 * xmlXPathCastNodeToString:
3246 * @node: a node
3247 *
3248 * Converts a node to its string value.
3249 *
3250 * Returns a newly allocated string.
3251 */
3252xmlChar *
3253xmlXPathCastNodeToString (xmlNodePtr node) {
Daniel Veillard23b1f372002-04-18 15:50:05 +00003254 if ((node != NULL) && (node->type == XML_DOCUMENT_NODE))
3255 node = xmlDocGetRootElement((xmlDocPtr) node);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003256 return(xmlNodeGetContent(node));
3257}
3258
3259/**
3260 * xmlXPathCastNodeSetToString:
3261 * @ns: a node-set
3262 *
3263 * Converts a node-set to its string value.
3264 *
3265 * Returns a newly allocated string.
3266 */
3267xmlChar *
3268xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3269 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3270 return(xmlStrdup((const xmlChar *) ""));
3271
3272 xmlXPathNodeSetSort(ns);
3273 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3274}
3275
3276/**
3277 * xmlXPathCastToString:
3278 * @val: an XPath object
3279 *
3280 * Converts an existing object to its string() equivalent
3281 *
3282 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003283 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003284 * string object).
3285 */
3286xmlChar *
3287xmlXPathCastToString(xmlXPathObjectPtr val) {
3288 xmlChar *ret = NULL;
3289
3290 if (val == NULL)
3291 return(xmlStrdup((const xmlChar *) ""));
3292 switch (val->type) {
3293 case XPATH_UNDEFINED:
3294#ifdef DEBUG_EXPR
3295 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3296#endif
3297 ret = xmlStrdup((const xmlChar *) "");
3298 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003299 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003300 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003301 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3302 break;
3303 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00003304 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003305 case XPATH_BOOLEAN:
3306 ret = xmlXPathCastBooleanToString(val->boolval);
3307 break;
3308 case XPATH_NUMBER: {
3309 ret = xmlXPathCastNumberToString(val->floatval);
3310 break;
3311 }
3312 case XPATH_USERS:
3313 case XPATH_POINT:
3314 case XPATH_RANGE:
3315 case XPATH_LOCATIONSET:
3316 TODO
3317 ret = xmlStrdup((const xmlChar *) "");
3318 break;
3319 }
3320 return(ret);
3321}
3322
3323/**
3324 * xmlXPathConvertString:
3325 * @val: an XPath object
3326 *
3327 * Converts an existing object to its string() equivalent
3328 *
3329 * Returns the new object, the old one is freed (or the operation
3330 * is done directly on @val)
3331 */
3332xmlXPathObjectPtr
3333xmlXPathConvertString(xmlXPathObjectPtr val) {
3334 xmlChar *res = NULL;
3335
3336 if (val == NULL)
3337 return(xmlXPathNewCString(""));
3338
3339 switch (val->type) {
3340 case XPATH_UNDEFINED:
3341#ifdef DEBUG_EXPR
3342 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3343#endif
3344 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003345 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003346 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003347 res = xmlXPathCastNodeSetToString(val->nodesetval);
3348 break;
3349 case XPATH_STRING:
3350 return(val);
3351 case XPATH_BOOLEAN:
3352 res = xmlXPathCastBooleanToString(val->boolval);
3353 break;
3354 case XPATH_NUMBER:
3355 res = xmlXPathCastNumberToString(val->floatval);
3356 break;
3357 case XPATH_USERS:
3358 case XPATH_POINT:
3359 case XPATH_RANGE:
3360 case XPATH_LOCATIONSET:
3361 TODO;
3362 break;
3363 }
3364 xmlXPathFreeObject(val);
3365 if (res == NULL)
3366 return(xmlXPathNewCString(""));
3367 return(xmlXPathWrapString(res));
3368}
3369
3370/**
3371 * xmlXPathCastBooleanToNumber:
3372 * @val: a boolean
3373 *
3374 * Converts a boolean to its number value
3375 *
3376 * Returns the number value
3377 */
3378double
3379xmlXPathCastBooleanToNumber(int val) {
3380 if (val)
3381 return(1.0);
3382 return(0.0);
3383}
3384
3385/**
3386 * xmlXPathCastStringToNumber:
3387 * @val: a string
3388 *
3389 * Converts a string to its number value
3390 *
3391 * Returns the number value
3392 */
3393double
3394xmlXPathCastStringToNumber(const xmlChar * val) {
3395 return(xmlXPathStringEvalNumber(val));
3396}
3397
3398/**
3399 * xmlXPathCastNodeToNumber:
3400 * @node: a node
3401 *
3402 * Converts a node to its number value
3403 *
3404 * Returns the number value
3405 */
3406double
3407xmlXPathCastNodeToNumber (xmlNodePtr node) {
3408 xmlChar *strval;
3409 double ret;
3410
3411 if (node == NULL)
3412 return(xmlXPathNAN);
3413 strval = xmlXPathCastNodeToString(node);
3414 if (strval == NULL)
3415 return(xmlXPathNAN);
3416 ret = xmlXPathCastStringToNumber(strval);
3417 xmlFree(strval);
3418
3419 return(ret);
3420}
3421
3422/**
3423 * xmlXPathCastNodeSetToNumber:
3424 * @ns: a node-set
3425 *
3426 * Converts a node-set to its number value
3427 *
3428 * Returns the number value
3429 */
3430double
3431xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3432 xmlChar *str;
3433 double ret;
3434
3435 if (ns == NULL)
3436 return(xmlXPathNAN);
3437 str = xmlXPathCastNodeSetToString(ns);
3438 ret = xmlXPathCastStringToNumber(str);
3439 xmlFree(str);
3440 return(ret);
3441}
3442
3443/**
3444 * xmlXPathCastToNumber:
3445 * @val: an XPath object
3446 *
3447 * Converts an XPath object to its number value
3448 *
3449 * Returns the number value
3450 */
3451double
3452xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3453 double ret = 0.0;
3454
3455 if (val == NULL)
3456 return(xmlXPathNAN);
3457 switch (val->type) {
3458 case XPATH_UNDEFINED:
3459#ifdef DEGUB_EXPR
3460 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3461#endif
3462 ret = xmlXPathNAN;
3463 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003464 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003465 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003466 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3467 break;
3468 case XPATH_STRING:
3469 ret = xmlXPathCastStringToNumber(val->stringval);
3470 break;
3471 case XPATH_NUMBER:
3472 ret = val->floatval;
3473 break;
3474 case XPATH_BOOLEAN:
3475 ret = xmlXPathCastBooleanToNumber(val->boolval);
3476 break;
3477 case XPATH_USERS:
3478 case XPATH_POINT:
3479 case XPATH_RANGE:
3480 case XPATH_LOCATIONSET:
3481 TODO;
3482 ret = xmlXPathNAN;
3483 break;
3484 }
3485 return(ret);
3486}
3487
3488/**
3489 * xmlXPathConvertNumber:
3490 * @val: an XPath object
3491 *
3492 * Converts an existing object to its number() equivalent
3493 *
3494 * Returns the new object, the old one is freed (or the operation
3495 * is done directly on @val)
3496 */
3497xmlXPathObjectPtr
3498xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3499 xmlXPathObjectPtr ret;
3500
3501 if (val == NULL)
3502 return(xmlXPathNewFloat(0.0));
3503 if (val->type == XPATH_NUMBER)
3504 return(val);
3505 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3506 xmlXPathFreeObject(val);
3507 return(ret);
3508}
3509
3510/**
3511 * xmlXPathCastNumberToBoolean:
3512 * @val: a number
3513 *
3514 * Converts a number to its boolean value
3515 *
3516 * Returns the boolean value
3517 */
3518int
3519xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003520 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003521 return(0);
3522 return(1);
3523}
3524
3525/**
3526 * xmlXPathCastStringToBoolean:
3527 * @val: a string
3528 *
3529 * Converts a string to its boolean value
3530 *
3531 * Returns the boolean value
3532 */
3533int
3534xmlXPathCastStringToBoolean (const xmlChar *val) {
3535 if ((val == NULL) || (xmlStrlen(val) == 0))
3536 return(0);
3537 return(1);
3538}
3539
3540/**
3541 * xmlXPathCastNodeSetToBoolean:
3542 * @ns: a node-set
3543 *
3544 * Converts a node-set to its boolean value
3545 *
3546 * Returns the boolean value
3547 */
3548int
3549xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3550 if ((ns == NULL) || (ns->nodeNr == 0))
3551 return(0);
3552 return(1);
3553}
3554
3555/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003556 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003557 * @val: an XPath object
3558 *
3559 * Converts an XPath object to its boolean value
3560 *
3561 * Returns the boolean value
3562 */
3563int
3564xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3565 int ret = 0;
3566
3567 if (val == NULL)
3568 return(0);
3569 switch (val->type) {
3570 case XPATH_UNDEFINED:
3571#ifdef DEBUG_EXPR
3572 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3573#endif
3574 ret = 0;
3575 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003576 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003577 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003578 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3579 break;
3580 case XPATH_STRING:
3581 ret = xmlXPathCastStringToBoolean(val->stringval);
3582 break;
3583 case XPATH_NUMBER:
3584 ret = xmlXPathCastNumberToBoolean(val->floatval);
3585 break;
3586 case XPATH_BOOLEAN:
3587 ret = val->boolval;
3588 break;
3589 case XPATH_USERS:
3590 case XPATH_POINT:
3591 case XPATH_RANGE:
3592 case XPATH_LOCATIONSET:
3593 TODO;
3594 ret = 0;
3595 break;
3596 }
3597 return(ret);
3598}
3599
3600
3601/**
3602 * xmlXPathConvertBoolean:
3603 * @val: an XPath object
3604 *
3605 * Converts an existing object to its boolean() equivalent
3606 *
3607 * Returns the new object, the old one is freed (or the operation
3608 * is done directly on @val)
3609 */
3610xmlXPathObjectPtr
3611xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3612 xmlXPathObjectPtr ret;
3613
3614 if (val == NULL)
3615 return(xmlXPathNewBoolean(0));
3616 if (val->type == XPATH_BOOLEAN)
3617 return(val);
3618 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3619 xmlXPathFreeObject(val);
3620 return(ret);
3621}
3622
Owen Taylor3473f882001-02-23 17:55:21 +00003623/************************************************************************
3624 * *
3625 * Routines to handle XPath contexts *
3626 * *
3627 ************************************************************************/
3628
3629/**
3630 * xmlXPathNewContext:
3631 * @doc: the XML document
3632 *
3633 * Create a new xmlXPathContext
3634 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00003635 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00003636 */
3637xmlXPathContextPtr
3638xmlXPathNewContext(xmlDocPtr doc) {
3639 xmlXPathContextPtr ret;
3640
3641 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3642 if (ret == NULL) {
3643 xmlGenericError(xmlGenericErrorContext,
3644 "xmlXPathNewContext: out of memory\n");
3645 return(NULL);
3646 }
3647 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3648 ret->doc = doc;
3649 ret->node = NULL;
3650
3651 ret->varHash = NULL;
3652
3653 ret->nb_types = 0;
3654 ret->max_types = 0;
3655 ret->types = NULL;
3656
3657 ret->funcHash = xmlHashCreate(0);
3658
3659 ret->nb_axis = 0;
3660 ret->max_axis = 0;
3661 ret->axis = NULL;
3662
3663 ret->nsHash = NULL;
3664 ret->user = NULL;
3665
3666 ret->contextSize = -1;
3667 ret->proximityPosition = -1;
3668
3669 xmlXPathRegisterAllFunctions(ret);
3670
3671 return(ret);
3672}
3673
3674/**
3675 * xmlXPathFreeContext:
3676 * @ctxt: the context to free
3677 *
3678 * Free up an xmlXPathContext
3679 */
3680void
3681xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3682 xmlXPathRegisteredNsCleanup(ctxt);
3683 xmlXPathRegisteredFuncsCleanup(ctxt);
3684 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003685 xmlFree(ctxt);
3686}
3687
3688/************************************************************************
3689 * *
3690 * Routines to handle XPath parser contexts *
3691 * *
3692 ************************************************************************/
3693
3694#define CHECK_CTXT(ctxt) \
3695 if (ctxt == NULL) { \
3696 xmlGenericError(xmlGenericErrorContext, \
3697 "%s:%d Internal error: ctxt == NULL\n", \
3698 __FILE__, __LINE__); \
3699 } \
3700
3701
3702#define CHECK_CONTEXT(ctxt) \
3703 if (ctxt == NULL) { \
3704 xmlGenericError(xmlGenericErrorContext, \
3705 "%s:%d Internal error: no context\n", \
3706 __FILE__, __LINE__); \
3707 } \
3708 else if (ctxt->doc == NULL) { \
3709 xmlGenericError(xmlGenericErrorContext, \
3710 "%s:%d Internal error: no document\n", \
3711 __FILE__, __LINE__); \
3712 } \
3713 else if (ctxt->doc->children == NULL) { \
3714 xmlGenericError(xmlGenericErrorContext, \
3715 "%s:%d Internal error: document without root\n", \
3716 __FILE__, __LINE__); \
3717 } \
3718
3719
3720/**
3721 * xmlXPathNewParserContext:
3722 * @str: the XPath expression
3723 * @ctxt: the XPath context
3724 *
3725 * Create a new xmlXPathParserContext
3726 *
3727 * Returns the xmlXPathParserContext just allocated.
3728 */
3729xmlXPathParserContextPtr
3730xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3731 xmlXPathParserContextPtr ret;
3732
3733 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3734 if (ret == NULL) {
3735 xmlGenericError(xmlGenericErrorContext,
3736 "xmlXPathNewParserContext: out of memory\n");
3737 return(NULL);
3738 }
3739 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3740 ret->cur = ret->base = str;
3741 ret->context = ctxt;
3742
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003743 ret->comp = xmlXPathNewCompExpr();
3744 if (ret->comp == NULL) {
3745 xmlFree(ret->valueTab);
3746 xmlFree(ret);
3747 return(NULL);
3748 }
3749
3750 return(ret);
3751}
3752
3753/**
3754 * xmlXPathCompParserContext:
3755 * @comp: the XPath compiled expression
3756 * @ctxt: the XPath context
3757 *
3758 * Create a new xmlXPathParserContext when processing a compiled expression
3759 *
3760 * Returns the xmlXPathParserContext just allocated.
3761 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003762static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003763xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3764 xmlXPathParserContextPtr ret;
3765
3766 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3767 if (ret == NULL) {
3768 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003769 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003770 return(NULL);
3771 }
3772 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3773
Owen Taylor3473f882001-02-23 17:55:21 +00003774 /* Allocate the value stack */
3775 ret->valueTab = (xmlXPathObjectPtr *)
3776 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003777 if (ret->valueTab == NULL) {
3778 xmlFree(ret);
3779 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003780 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003781 return(NULL);
3782 }
Owen Taylor3473f882001-02-23 17:55:21 +00003783 ret->valueNr = 0;
3784 ret->valueMax = 10;
3785 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003786
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00003787 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003788 ret->comp = comp;
3789
Owen Taylor3473f882001-02-23 17:55:21 +00003790 return(ret);
3791}
3792
3793/**
3794 * xmlXPathFreeParserContext:
3795 * @ctxt: the context to free
3796 *
3797 * Free up an xmlXPathParserContext
3798 */
3799void
3800xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
3801 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003802 xmlFree(ctxt->valueTab);
3803 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003804 if (ctxt->comp)
3805 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00003806 xmlFree(ctxt);
3807}
3808
3809/************************************************************************
3810 * *
3811 * The implicit core function library *
3812 * *
3813 ************************************************************************/
3814
Owen Taylor3473f882001-02-23 17:55:21 +00003815/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00003816 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00003817 * @node: a node pointer
3818 *
3819 * Function computing the beginning of the string value of the node,
3820 * used to speed up comparisons
3821 *
3822 * Returns an int usable as a hash
3823 */
3824static unsigned int
3825xmlXPathNodeValHash(xmlNodePtr node) {
3826 int len = 2;
3827 const xmlChar * string = NULL;
3828 xmlNodePtr tmp = NULL;
3829 unsigned int ret = 0;
3830
3831 if (node == NULL)
3832 return(0);
3833
3834
3835 switch (node->type) {
3836 case XML_COMMENT_NODE:
3837 case XML_PI_NODE:
3838 case XML_CDATA_SECTION_NODE:
3839 case XML_TEXT_NODE:
3840 string = node->content;
3841 if (string == NULL)
3842 return(0);
3843 if (string[0] == 0)
3844 return(0);
3845 return(((unsigned int) string[0]) +
3846 (((unsigned int) string[1]) << 8));
3847 case XML_NAMESPACE_DECL:
3848 string = ((xmlNsPtr)node)->href;
3849 if (string == NULL)
3850 return(0);
3851 if (string[0] == 0)
3852 return(0);
3853 return(((unsigned int) string[0]) +
3854 (((unsigned int) string[1]) << 8));
3855 case XML_ATTRIBUTE_NODE:
3856 tmp = ((xmlAttrPtr) node)->children;
3857 break;
3858 case XML_ELEMENT_NODE:
3859 tmp = node->children;
3860 break;
3861 default:
3862 return(0);
3863 }
3864 while (tmp != NULL) {
3865 switch (tmp->type) {
3866 case XML_COMMENT_NODE:
3867 case XML_PI_NODE:
3868 case XML_CDATA_SECTION_NODE:
3869 case XML_TEXT_NODE:
3870 string = tmp->content;
3871 break;
3872 case XML_NAMESPACE_DECL:
3873 string = ((xmlNsPtr)tmp)->href;
3874 break;
3875 default:
3876 break;
3877 }
3878 if ((string != NULL) && (string[0] != 0)) {
3879 if (string[0] == 0)
3880 return(0);
3881 if (len == 1) {
3882 return(ret + (((unsigned int) string[0]) << 8));
3883 }
3884 if (string[1] == 0) {
3885 len = 1;
3886 ret = (unsigned int) string[0];
3887 } else {
3888 return(((unsigned int) string[0]) +
3889 (((unsigned int) string[1]) << 8));
3890 }
3891 }
3892 /*
3893 * Skip to next node
3894 */
3895 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
3896 if (tmp->children->type != XML_ENTITY_DECL) {
3897 tmp = tmp->children;
3898 continue;
3899 }
3900 }
3901 if (tmp == node)
3902 break;
3903
3904 if (tmp->next != NULL) {
3905 tmp = tmp->next;
3906 continue;
3907 }
3908
3909 do {
3910 tmp = tmp->parent;
3911 if (tmp == NULL)
3912 break;
3913 if (tmp == node) {
3914 tmp = NULL;
3915 break;
3916 }
3917 if (tmp->next != NULL) {
3918 tmp = tmp->next;
3919 break;
3920 }
3921 } while (tmp != NULL);
3922 }
3923 return(ret);
3924}
3925
3926/**
3927 * xmlXPathStringHash:
3928 * @string: a string
3929 *
3930 * Function computing the beginning of the string value of the node,
3931 * used to speed up comparisons
3932 *
3933 * Returns an int usable as a hash
3934 */
3935static unsigned int
3936xmlXPathStringHash(const xmlChar * string) {
3937 if (string == NULL)
3938 return((unsigned int) 0);
3939 if (string[0] == 0)
3940 return(0);
3941 return(((unsigned int) string[0]) +
3942 (((unsigned int) string[1]) << 8));
3943}
3944
3945/**
Owen Taylor3473f882001-02-23 17:55:21 +00003946 * xmlXPathCompareNodeSetFloat:
3947 * @ctxt: the XPath Parser context
3948 * @inf: less than (1) or greater than (0)
3949 * @strict: is the comparison strict
3950 * @arg: the node set
3951 * @f: the value
3952 *
3953 * Implement the compare operation between a nodeset and a number
3954 * @ns < @val (1, 1, ...
3955 * @ns <= @val (1, 0, ...
3956 * @ns > @val (0, 1, ...
3957 * @ns >= @val (0, 0, ...
3958 *
3959 * If one object to be compared is a node-set and the other is a number,
3960 * then the comparison will be true if and only if there is a node in the
3961 * node-set such that the result of performing the comparison on the number
3962 * to be compared and on the result of converting the string-value of that
3963 * node to a number using the number function is true.
3964 *
3965 * Returns 0 or 1 depending on the results of the test.
3966 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003967static int
Owen Taylor3473f882001-02-23 17:55:21 +00003968xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
3969 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
3970 int i, ret = 0;
3971 xmlNodeSetPtr ns;
3972 xmlChar *str2;
3973
3974 if ((f == NULL) || (arg == NULL) ||
3975 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3976 xmlXPathFreeObject(arg);
3977 xmlXPathFreeObject(f);
3978 return(0);
3979 }
3980 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003981 if (ns != NULL) {
3982 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003983 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003984 if (str2 != NULL) {
3985 valuePush(ctxt,
3986 xmlXPathNewString(str2));
3987 xmlFree(str2);
3988 xmlXPathNumberFunction(ctxt, 1);
3989 valuePush(ctxt, xmlXPathObjectCopy(f));
3990 ret = xmlXPathCompareValues(ctxt, inf, strict);
3991 if (ret)
3992 break;
3993 }
3994 }
Owen Taylor3473f882001-02-23 17:55:21 +00003995 }
3996 xmlXPathFreeObject(arg);
3997 xmlXPathFreeObject(f);
3998 return(ret);
3999}
4000
4001/**
4002 * xmlXPathCompareNodeSetString:
4003 * @ctxt: the XPath Parser context
4004 * @inf: less than (1) or greater than (0)
4005 * @strict: is the comparison strict
4006 * @arg: the node set
4007 * @s: the value
4008 *
4009 * Implement the compare operation between a nodeset and a string
4010 * @ns < @val (1, 1, ...
4011 * @ns <= @val (1, 0, ...
4012 * @ns > @val (0, 1, ...
4013 * @ns >= @val (0, 0, ...
4014 *
4015 * If one object to be compared is a node-set and the other is a string,
4016 * then the comparison will be true if and only if there is a node in
4017 * the node-set such that the result of performing the comparison on the
4018 * string-value of the node and the other string is true.
4019 *
4020 * Returns 0 or 1 depending on the results of the test.
4021 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004022static int
Owen Taylor3473f882001-02-23 17:55:21 +00004023xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
4024 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
4025 int i, ret = 0;
4026 xmlNodeSetPtr ns;
4027 xmlChar *str2;
4028
4029 if ((s == NULL) || (arg == NULL) ||
4030 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4031 xmlXPathFreeObject(arg);
4032 xmlXPathFreeObject(s);
4033 return(0);
4034 }
4035 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004036 if (ns != NULL) {
4037 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004038 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004039 if (str2 != NULL) {
4040 valuePush(ctxt,
4041 xmlXPathNewString(str2));
4042 xmlFree(str2);
4043 valuePush(ctxt, xmlXPathObjectCopy(s));
4044 ret = xmlXPathCompareValues(ctxt, inf, strict);
4045 if (ret)
4046 break;
4047 }
4048 }
Owen Taylor3473f882001-02-23 17:55:21 +00004049 }
4050 xmlXPathFreeObject(arg);
4051 xmlXPathFreeObject(s);
4052 return(ret);
4053}
4054
4055/**
4056 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004057 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00004058 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004059 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00004060 * @arg2: the second node set object
4061 *
4062 * Implement the compare operation on nodesets:
4063 *
4064 * If both objects to be compared are node-sets, then the comparison
4065 * will be true if and only if there is a node in the first node-set
4066 * and a node in the second node-set such that the result of performing
4067 * the comparison on the string-values of the two nodes is true.
4068 * ....
4069 * When neither object to be compared is a node-set and the operator
4070 * is <=, <, >= or >, then the objects are compared by converting both
4071 * objects to numbers and comparing the numbers according to IEEE 754.
4072 * ....
4073 * The number function converts its argument to a number as follows:
4074 * - a string that consists of optional whitespace followed by an
4075 * optional minus sign followed by a Number followed by whitespace
4076 * is converted to the IEEE 754 number that is nearest (according
4077 * to the IEEE 754 round-to-nearest rule) to the mathematical value
4078 * represented by the string; any other string is converted to NaN
4079 *
4080 * Conclusion all nodes need to be converted first to their string value
4081 * and then the comparison must be done when possible
4082 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004083static int
4084xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00004085 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4086 int i, j, init = 0;
4087 double val1;
4088 double *values2;
4089 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004090 xmlNodeSetPtr ns1;
4091 xmlNodeSetPtr ns2;
4092
4093 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004094 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4095 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004096 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004097 }
Owen Taylor3473f882001-02-23 17:55:21 +00004098 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004099 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4100 xmlXPathFreeObject(arg1);
4101 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004102 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004103 }
Owen Taylor3473f882001-02-23 17:55:21 +00004104
4105 ns1 = arg1->nodesetval;
4106 ns2 = arg2->nodesetval;
4107
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004108 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004109 xmlXPathFreeObject(arg1);
4110 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004111 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004112 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004113 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004114 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 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4120 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004121 xmlXPathFreeObject(arg1);
4122 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004123 return(0);
4124 }
4125 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004126 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004127 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004128 continue;
4129 for (j = 0;j < ns2->nodeNr;j++) {
4130 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004131 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004132 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004133 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004134 continue;
4135 if (inf && strict)
4136 ret = (val1 < values2[j]);
4137 else if (inf && !strict)
4138 ret = (val1 <= values2[j]);
4139 else if (!inf && strict)
4140 ret = (val1 > values2[j]);
4141 else if (!inf && !strict)
4142 ret = (val1 >= values2[j]);
4143 if (ret)
4144 break;
4145 }
4146 if (ret)
4147 break;
4148 init = 1;
4149 }
4150 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004151 xmlXPathFreeObject(arg1);
4152 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004153 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004154}
4155
4156/**
4157 * xmlXPathCompareNodeSetValue:
4158 * @ctxt: the XPath Parser context
4159 * @inf: less than (1) or greater than (0)
4160 * @strict: is the comparison strict
4161 * @arg: the node set
4162 * @val: the value
4163 *
4164 * Implement the compare operation between a nodeset and a value
4165 * @ns < @val (1, 1, ...
4166 * @ns <= @val (1, 0, ...
4167 * @ns > @val (0, 1, ...
4168 * @ns >= @val (0, 0, ...
4169 *
4170 * If one object to be compared is a node-set and the other is a boolean,
4171 * then the comparison will be true if and only if the result of performing
4172 * the comparison on the boolean and on the result of converting
4173 * the node-set to a boolean using the boolean function is true.
4174 *
4175 * Returns 0 or 1 depending on the results of the test.
4176 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004177static int
Owen Taylor3473f882001-02-23 17:55:21 +00004178xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4179 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4180 if ((val == NULL) || (arg == NULL) ||
4181 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4182 return(0);
4183
4184 switch(val->type) {
4185 case XPATH_NUMBER:
4186 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4187 case XPATH_NODESET:
4188 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004189 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004190 case XPATH_STRING:
4191 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4192 case XPATH_BOOLEAN:
4193 valuePush(ctxt, arg);
4194 xmlXPathBooleanFunction(ctxt, 1);
4195 valuePush(ctxt, val);
4196 return(xmlXPathCompareValues(ctxt, inf, strict));
4197 default:
4198 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004199 }
4200 return(0);
4201}
4202
4203/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004204 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00004205 * @arg: the nodeset object argument
4206 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00004207 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004208 *
4209 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4210 * If one object to be compared is a node-set and the other is a string,
4211 * then the comparison will be true if and only if there is a node in
4212 * the node-set such that the result of performing the comparison on the
4213 * string-value of the node and the other string is true.
4214 *
4215 * Returns 0 or 1 depending on the results of the test.
4216 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004217static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004218xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004219{
Owen Taylor3473f882001-02-23 17:55:21 +00004220 int i;
4221 xmlNodeSetPtr ns;
4222 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004223 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004224
4225 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004226 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4227 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004228 ns = arg->nodesetval;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004229 hash = xmlXPathStringHash(str);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004230 if (ns == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004231 return (0);
Daniel Veillard73c9c042001-07-05 20:02:54 +00004232 if (ns->nodeNr <= 0) {
4233 if (hash == 0)
William M. Brack0c022ad2002-07-12 00:56:01 +00004234 return(neq ^ 1);
4235 return(neq);
Daniel Veillard73c9c042001-07-05 20:02:54 +00004236 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004237 for (i = 0; i < ns->nodeNr; i++) {
4238 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4239 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4240 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4241 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004242 if (neq)
4243 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004244 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00004245 } else if (neq) {
4246 if (str2 != NULL)
4247 xmlFree(str2);
4248 return (1);
4249 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004250 if (str2 != NULL)
4251 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004252 } else if (neq)
4253 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00004254 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004255 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004256}
4257
4258/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004259 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00004260 * @arg: the nodeset object argument
4261 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00004262 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004263 *
4264 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4265 * If one object to be compared is a node-set and the other is a number,
4266 * then the comparison will be true if and only if there is a node in
4267 * the node-set such that the result of performing the comparison on the
4268 * number to be compared and on the result of converting the string-value
4269 * of that node to a number using the number function is true.
4270 *
4271 * Returns 0 or 1 depending on the results of the test.
4272 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004273static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004274xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
4275 xmlXPathObjectPtr arg, double f, int neq) {
4276 int i, ret=0;
4277 xmlNodeSetPtr ns;
4278 xmlChar *str2;
4279 xmlXPathObjectPtr val;
4280 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00004281
4282 if ((arg == NULL) ||
4283 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4284 return(0);
4285
William M. Brack0c022ad2002-07-12 00:56:01 +00004286 ns = arg->nodesetval;
4287 if (ns != NULL) {
4288 for (i=0;i<ns->nodeNr;i++) {
4289 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4290 if (str2 != NULL) {
4291 valuePush(ctxt, xmlXPathNewString(str2));
4292 xmlFree(str2);
4293 xmlXPathNumberFunction(ctxt, 1);
4294 val = valuePop(ctxt);
4295 v = val->floatval;
4296 xmlXPathFreeObject(val);
4297 if (!xmlXPathIsNaN(v)) {
4298 if ((!neq) && (v==f)) {
4299 ret = 1;
4300 break;
4301 } else if ((neq) && (v!=f)) {
4302 ret = 1;
4303 break;
4304 }
4305 }
4306 }
4307 }
4308 }
4309
4310 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004311}
4312
4313
4314/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004315 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00004316 * @arg1: first nodeset object argument
4317 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00004318 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004319 *
William M. Brack0c022ad2002-07-12 00:56:01 +00004320 * Implement the equal / not equal operation on XPath nodesets:
4321 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00004322 * If both objects to be compared are node-sets, then the comparison
4323 * will be true if and only if there is a node in the first node-set and
4324 * a node in the second node-set such that the result of performing the
4325 * comparison on the string-values of the two nodes is true.
4326 *
4327 * (needless to say, this is a costly operation)
4328 *
4329 * Returns 0 or 1 depending on the results of the test.
4330 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004331static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004332xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00004333 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004334 unsigned int *hashs1;
4335 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004336 xmlChar **values1;
4337 xmlChar **values2;
4338 int ret = 0;
4339 xmlNodeSetPtr ns1;
4340 xmlNodeSetPtr ns2;
4341
4342 if ((arg1 == NULL) ||
4343 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4344 return(0);
4345 if ((arg2 == NULL) ||
4346 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4347 return(0);
4348
4349 ns1 = arg1->nodesetval;
4350 ns2 = arg2->nodesetval;
4351
Daniel Veillard911f49a2001-04-07 15:39:35 +00004352 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004353 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004354 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004355 return(0);
4356
4357 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00004358 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00004359 */
William M. Brack0c022ad2002-07-12 00:56:01 +00004360 if (neq == 0)
4361 for (i = 0;i < ns1->nodeNr;i++)
4362 for (j = 0;j < ns2->nodeNr;j++)
4363 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4364 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00004365
4366 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
4367 if (values1 == NULL)
4368 return(0);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004369 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4370 if (hashs1 == NULL) {
4371 xmlFree(values1);
4372 return(0);
4373 }
Owen Taylor3473f882001-02-23 17:55:21 +00004374 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4375 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4376 if (values2 == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004377 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004378 xmlFree(values1);
4379 return(0);
4380 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004381 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4382 if (hashs2 == NULL) {
4383 xmlFree(hashs1);
4384 xmlFree(values1);
4385 xmlFree(values2);
4386 return(0);
4387 }
Owen Taylor3473f882001-02-23 17:55:21 +00004388 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4389 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004390 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004391 for (j = 0;j < ns2->nodeNr;j++) {
4392 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004393 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004394 if (hashs1[i] != hashs2[j]) {
4395 if (neq) {
4396 ret = 1;
4397 break;
4398 }
4399 }
4400 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004401 if (values1[i] == NULL)
4402 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4403 if (values2[j] == NULL)
4404 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004405 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004406 if (ret)
4407 break;
4408 }
Owen Taylor3473f882001-02-23 17:55:21 +00004409 }
4410 if (ret)
4411 break;
4412 }
4413 for (i = 0;i < ns1->nodeNr;i++)
4414 if (values1[i] != NULL)
4415 xmlFree(values1[i]);
4416 for (j = 0;j < ns2->nodeNr;j++)
4417 if (values2[j] != NULL)
4418 xmlFree(values2[j]);
4419 xmlFree(values1);
4420 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004421 xmlFree(hashs1);
4422 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004423 return(ret);
4424}
4425
William M. Brack0c022ad2002-07-12 00:56:01 +00004426static int
4427xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
4428 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00004429 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00004430 /*
4431 *At this point we are assured neither arg1 nor arg2
4432 *is a nodeset, so we can just pick the appropriate routine.
4433 */
Owen Taylor3473f882001-02-23 17:55:21 +00004434 switch (arg1->type) {
4435 case XPATH_UNDEFINED:
4436#ifdef DEBUG_EXPR
4437 xmlGenericError(xmlGenericErrorContext,
4438 "Equal: undefined\n");
4439#endif
4440 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004441 case XPATH_BOOLEAN:
4442 switch (arg2->type) {
4443 case XPATH_UNDEFINED:
4444#ifdef DEBUG_EXPR
4445 xmlGenericError(xmlGenericErrorContext,
4446 "Equal: undefined\n");
4447#endif
4448 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004449 case XPATH_BOOLEAN:
4450#ifdef DEBUG_EXPR
4451 xmlGenericError(xmlGenericErrorContext,
4452 "Equal: %d boolean %d \n",
4453 arg1->boolval, arg2->boolval);
4454#endif
4455 ret = (arg1->boolval == arg2->boolval);
4456 break;
4457 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00004458 ret = (arg1->boolval ==
4459 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004460 break;
4461 case XPATH_STRING:
4462 if ((arg2->stringval == NULL) ||
4463 (arg2->stringval[0] == 0)) ret = 0;
4464 else
4465 ret = 1;
4466 ret = (arg1->boolval == ret);
4467 break;
4468 case XPATH_USERS:
4469 case XPATH_POINT:
4470 case XPATH_RANGE:
4471 case XPATH_LOCATIONSET:
4472 TODO
4473 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004474 case XPATH_NODESET:
4475 case XPATH_XSLT_TREE:
4476 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004477 }
4478 break;
4479 case XPATH_NUMBER:
4480 switch (arg2->type) {
4481 case XPATH_UNDEFINED:
4482#ifdef DEBUG_EXPR
4483 xmlGenericError(xmlGenericErrorContext,
4484 "Equal: undefined\n");
4485#endif
4486 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004487 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00004488 ret = (arg2->boolval==
4489 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004490 break;
4491 case XPATH_STRING:
4492 valuePush(ctxt, arg2);
4493 xmlXPathNumberFunction(ctxt, 1);
4494 arg2 = valuePop(ctxt);
4495 /* no break on purpose */
4496 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004497 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004498 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4499 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004500 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4501 if (xmlXPathIsInf(arg2->floatval) == 1)
4502 ret = 1;
4503 else
4504 ret = 0;
4505 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4506 if (xmlXPathIsInf(arg2->floatval) == -1)
4507 ret = 1;
4508 else
4509 ret = 0;
4510 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4511 if (xmlXPathIsInf(arg1->floatval) == 1)
4512 ret = 1;
4513 else
4514 ret = 0;
4515 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4516 if (xmlXPathIsInf(arg1->floatval) == -1)
4517 ret = 1;
4518 else
4519 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004520 } else {
4521 ret = (arg1->floatval == arg2->floatval);
4522 }
Owen Taylor3473f882001-02-23 17:55:21 +00004523 break;
4524 case XPATH_USERS:
4525 case XPATH_POINT:
4526 case XPATH_RANGE:
4527 case XPATH_LOCATIONSET:
4528 TODO
4529 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004530 case XPATH_NODESET:
4531 case XPATH_XSLT_TREE:
4532 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004533 }
4534 break;
4535 case XPATH_STRING:
4536 switch (arg2->type) {
4537 case XPATH_UNDEFINED:
4538#ifdef DEBUG_EXPR
4539 xmlGenericError(xmlGenericErrorContext,
4540 "Equal: undefined\n");
4541#endif
4542 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004543 case XPATH_BOOLEAN:
4544 if ((arg1->stringval == NULL) ||
4545 (arg1->stringval[0] == 0)) ret = 0;
4546 else
4547 ret = 1;
4548 ret = (arg2->boolval == ret);
4549 break;
4550 case XPATH_STRING:
4551 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4552 break;
4553 case XPATH_NUMBER:
4554 valuePush(ctxt, arg1);
4555 xmlXPathNumberFunction(ctxt, 1);
4556 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004557 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004558 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4559 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004560 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4561 if (xmlXPathIsInf(arg2->floatval) == 1)
4562 ret = 1;
4563 else
4564 ret = 0;
4565 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4566 if (xmlXPathIsInf(arg2->floatval) == -1)
4567 ret = 1;
4568 else
4569 ret = 0;
4570 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4571 if (xmlXPathIsInf(arg1->floatval) == 1)
4572 ret = 1;
4573 else
4574 ret = 0;
4575 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4576 if (xmlXPathIsInf(arg1->floatval) == -1)
4577 ret = 1;
4578 else
4579 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004580 } else {
4581 ret = (arg1->floatval == arg2->floatval);
4582 }
Owen Taylor3473f882001-02-23 17:55:21 +00004583 break;
4584 case XPATH_USERS:
4585 case XPATH_POINT:
4586 case XPATH_RANGE:
4587 case XPATH_LOCATIONSET:
4588 TODO
4589 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004590 case XPATH_NODESET:
4591 case XPATH_XSLT_TREE:
4592 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004593 }
4594 break;
4595 case XPATH_USERS:
4596 case XPATH_POINT:
4597 case XPATH_RANGE:
4598 case XPATH_LOCATIONSET:
4599 TODO
4600 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004601 case XPATH_NODESET:
4602 case XPATH_XSLT_TREE:
4603 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004604 }
4605 xmlXPathFreeObject(arg1);
4606 xmlXPathFreeObject(arg2);
4607 return(ret);
4608}
4609
William M. Brack0c022ad2002-07-12 00:56:01 +00004610/**
4611 * xmlXPathEqualValues:
4612 * @ctxt: the XPath Parser context
4613 *
4614 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4615 *
4616 * Returns 0 or 1 depending on the results of the test.
4617 */
4618int
4619xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4620 xmlXPathObjectPtr arg1, arg2, argtmp;
4621 int ret = 0;
4622
4623 arg2 = valuePop(ctxt);
4624 arg1 = valuePop(ctxt);
4625 if ((arg1 == NULL) || (arg2 == NULL)) {
4626 if (arg1 != NULL)
4627 xmlXPathFreeObject(arg1);
4628 else
4629 xmlXPathFreeObject(arg2);
4630 XP_ERROR0(XPATH_INVALID_OPERAND);
4631 }
4632
4633 if (arg1 == arg2) {
4634#ifdef DEBUG_EXPR
4635 xmlGenericError(xmlGenericErrorContext,
4636 "Equal: by pointer\n");
4637#endif
4638 return(1);
4639 }
4640
4641 /*
4642 *If either argument is a nodeset, it's a 'special case'
4643 */
4644 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4645 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4646 /*
4647 *Hack it to assure arg1 is the nodeset
4648 */
4649 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4650 argtmp = arg2;
4651 arg2 = arg1;
4652 arg1 = argtmp;
4653 }
4654 switch (arg2->type) {
4655 case XPATH_UNDEFINED:
4656#ifdef DEBUG_EXPR
4657 xmlGenericError(xmlGenericErrorContext,
4658 "Equal: undefined\n");
4659#endif
4660 break;
4661 case XPATH_NODESET:
4662 case XPATH_XSLT_TREE:
4663 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
4664 break;
4665 case XPATH_BOOLEAN:
4666 if ((arg1->nodesetval == NULL) ||
4667 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4668 else
4669 ret = 1;
4670 ret = (ret == arg2->boolval);
4671 break;
4672 case XPATH_NUMBER:
4673 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
4674 break;
4675 case XPATH_STRING:
4676 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
4677 break;
4678 case XPATH_USERS:
4679 case XPATH_POINT:
4680 case XPATH_RANGE:
4681 case XPATH_LOCATIONSET:
4682 TODO
4683 break;
4684 }
4685 xmlXPathFreeObject(arg1);
4686 xmlXPathFreeObject(arg2);
4687 return(ret);
4688 }
4689
4690 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4691}
4692
4693/**
4694 * xmlXPathNotEqualValues:
4695 * @ctxt: the XPath Parser context
4696 *
4697 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4698 *
4699 * Returns 0 or 1 depending on the results of the test.
4700 */
4701int
4702xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
4703 xmlXPathObjectPtr arg1, arg2, argtmp;
4704 int ret = 0;
4705
4706 arg2 = valuePop(ctxt);
4707 arg1 = valuePop(ctxt);
4708 if ((arg1 == NULL) || (arg2 == NULL)) {
4709 if (arg1 != NULL)
4710 xmlXPathFreeObject(arg1);
4711 else
4712 xmlXPathFreeObject(arg2);
4713 XP_ERROR0(XPATH_INVALID_OPERAND);
4714 }
4715
4716 if (arg1 == arg2) {
4717#ifdef DEBUG_EXPR
4718 xmlGenericError(xmlGenericErrorContext,
4719 "NotEqual: by pointer\n");
4720#endif
4721 return(0);
4722 }
4723
4724 /*
4725 *If either argument is a nodeset, it's a 'special case'
4726 */
4727 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4728 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4729 /*
4730 *Hack it to assure arg1 is the nodeset
4731 */
4732 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4733 argtmp = arg2;
4734 arg2 = arg1;
4735 arg1 = argtmp;
4736 }
4737 switch (arg2->type) {
4738 case XPATH_UNDEFINED:
4739#ifdef DEBUG_EXPR
4740 xmlGenericError(xmlGenericErrorContext,
4741 "NotEqual: undefined\n");
4742#endif
4743 break;
4744 case XPATH_NODESET:
4745 case XPATH_XSLT_TREE:
4746 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
4747 break;
4748 case XPATH_BOOLEAN:
4749 if ((arg1->nodesetval == NULL) ||
4750 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4751 else
4752 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00004753 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00004754 break;
4755 case XPATH_NUMBER:
4756 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
4757 break;
4758 case XPATH_STRING:
4759 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
4760 break;
4761 case XPATH_USERS:
4762 case XPATH_POINT:
4763 case XPATH_RANGE:
4764 case XPATH_LOCATIONSET:
4765 TODO
4766 break;
4767 }
4768 xmlXPathFreeObject(arg1);
4769 xmlXPathFreeObject(arg2);
4770 return(ret);
4771 }
4772
4773 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4774}
Owen Taylor3473f882001-02-23 17:55:21 +00004775
4776/**
4777 * xmlXPathCompareValues:
4778 * @ctxt: the XPath Parser context
4779 * @inf: less than (1) or greater than (0)
4780 * @strict: is the comparison strict
4781 *
4782 * Implement the compare operation on XPath objects:
4783 * @arg1 < @arg2 (1, 1, ...
4784 * @arg1 <= @arg2 (1, 0, ...
4785 * @arg1 > @arg2 (0, 1, ...
4786 * @arg1 >= @arg2 (0, 0, ...
4787 *
4788 * When neither object to be compared is a node-set and the operator is
4789 * <=, <, >=, >, then the objects are compared by converted both objects
4790 * to numbers and comparing the numbers according to IEEE 754. The <
4791 * comparison will be true if and only if the first number is less than the
4792 * second number. The <= comparison will be true if and only if the first
4793 * number is less than or equal to the second number. The > comparison
4794 * will be true if and only if the first number is greater than the second
4795 * number. The >= comparison will be true if and only if the first number
4796 * is greater than or equal to the second number.
4797 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004798 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00004799 */
4800int
4801xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004802 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004803 xmlXPathObjectPtr arg1, arg2;
4804
William M. Brack0c022ad2002-07-12 00:56:01 +00004805 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00004806 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00004807 if ((arg1 == NULL) || (arg2 == NULL)) {
4808 if (arg1 != NULL)
4809 xmlXPathFreeObject(arg1);
4810 else
4811 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004812 XP_ERROR0(XPATH_INVALID_OPERAND);
4813 }
4814
William M. Brack0c022ad2002-07-12 00:56:01 +00004815 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4816 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4817 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
4818 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004819 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004820 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00004821 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004822 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
4823 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004824 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004825 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
4826 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00004827 }
4828 }
4829 return(ret);
4830 }
4831
4832 if (arg1->type != XPATH_NUMBER) {
4833 valuePush(ctxt, arg1);
4834 xmlXPathNumberFunction(ctxt, 1);
4835 arg1 = valuePop(ctxt);
4836 }
4837 if (arg1->type != XPATH_NUMBER) {
4838 xmlXPathFreeObject(arg1);
4839 xmlXPathFreeObject(arg2);
4840 XP_ERROR0(XPATH_INVALID_OPERAND);
4841 }
4842 if (arg2->type != XPATH_NUMBER) {
4843 valuePush(ctxt, arg2);
4844 xmlXPathNumberFunction(ctxt, 1);
4845 arg2 = valuePop(ctxt);
4846 }
4847 if (arg2->type != XPATH_NUMBER) {
4848 xmlXPathFreeObject(arg1);
4849 xmlXPathFreeObject(arg2);
4850 XP_ERROR0(XPATH_INVALID_OPERAND);
4851 }
4852 /*
4853 * Add tests for infinity and nan
4854 * => feedback on 3.4 for Inf and NaN
4855 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004856 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00004857 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004858 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004859 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004860 arg1i=xmlXPathIsInf(arg1->floatval);
4861 arg2i=xmlXPathIsInf(arg2->floatval);
4862 if (inf && strict) {
4863 if ((arg1i == -1 && arg2i != -1) ||
4864 (arg2i == 1 && arg1i != 1)) {
4865 ret = 1;
4866 } else if (arg1i == 0 && arg2i == 0) {
4867 ret = (arg1->floatval < arg2->floatval);
4868 } else {
4869 ret = 0;
4870 }
4871 }
4872 else if (inf && !strict) {
4873 if (arg1i == -1 || arg2i == 1) {
4874 ret = 1;
4875 } else if (arg1i == 0 && arg2i == 0) {
4876 ret = (arg1->floatval <= arg2->floatval);
4877 } else {
4878 ret = 0;
4879 }
4880 }
4881 else if (!inf && strict) {
4882 if ((arg1i == 1 && arg2i != 1) ||
4883 (arg2i == -1 && arg1i != -1)) {
4884 ret = 1;
4885 } else if (arg1i == 0 && arg2i == 0) {
4886 ret = (arg1->floatval > arg2->floatval);
4887 } else {
4888 ret = 0;
4889 }
4890 }
4891 else if (!inf && !strict) {
4892 if (arg1i == 1 || arg2i == -1) {
4893 ret = 1;
4894 } else if (arg1i == 0 && arg2i == 0) {
4895 ret = (arg1->floatval >= arg2->floatval);
4896 } else {
4897 ret = 0;
4898 }
4899 }
Daniel Veillard21458c82002-03-27 16:12:22 +00004900 }
Owen Taylor3473f882001-02-23 17:55:21 +00004901 xmlXPathFreeObject(arg1);
4902 xmlXPathFreeObject(arg2);
4903 return(ret);
4904}
4905
4906/**
4907 * xmlXPathValueFlipSign:
4908 * @ctxt: the XPath Parser context
4909 *
4910 * Implement the unary - operation on an XPath object
4911 * The numeric operators convert their operands to numbers as if
4912 * by calling the number function.
4913 */
4914void
4915xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004916 CAST_TO_NUMBER;
4917 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00004918 if (xmlXPathIsNaN(ctxt->value->floatval))
4919 ctxt->value->floatval=xmlXPathNAN;
4920 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
4921 ctxt->value->floatval=xmlXPathNINF;
4922 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
4923 ctxt->value->floatval=xmlXPathPINF;
4924 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00004925 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
4926 ctxt->value->floatval = xmlXPathNZERO;
4927 else
4928 ctxt->value->floatval = 0;
4929 }
4930 else
4931 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00004932}
4933
4934/**
4935 * xmlXPathAddValues:
4936 * @ctxt: the XPath Parser context
4937 *
4938 * Implement the add operation on XPath objects:
4939 * The numeric operators convert their operands to numbers as if
4940 * by calling the number function.
4941 */
4942void
4943xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
4944 xmlXPathObjectPtr arg;
4945 double val;
4946
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004947 arg = valuePop(ctxt);
4948 if (arg == NULL)
4949 XP_ERROR(XPATH_INVALID_OPERAND);
4950 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004951 xmlXPathFreeObject(arg);
4952
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004953 CAST_TO_NUMBER;
4954 CHECK_TYPE(XPATH_NUMBER);
4955 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00004956}
4957
4958/**
4959 * xmlXPathSubValues:
4960 * @ctxt: the XPath Parser context
4961 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004962 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00004963 * The numeric operators convert their operands to numbers as if
4964 * by calling the number function.
4965 */
4966void
4967xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
4968 xmlXPathObjectPtr arg;
4969 double val;
4970
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004971 arg = valuePop(ctxt);
4972 if (arg == NULL)
4973 XP_ERROR(XPATH_INVALID_OPERAND);
4974 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004975 xmlXPathFreeObject(arg);
4976
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004977 CAST_TO_NUMBER;
4978 CHECK_TYPE(XPATH_NUMBER);
4979 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004980}
4981
4982/**
4983 * xmlXPathMultValues:
4984 * @ctxt: the XPath Parser context
4985 *
4986 * Implement the multiply operation on XPath objects:
4987 * The numeric operators convert their operands to numbers as if
4988 * by calling the number function.
4989 */
4990void
4991xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
4992 xmlXPathObjectPtr arg;
4993 double val;
4994
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004995 arg = valuePop(ctxt);
4996 if (arg == NULL)
4997 XP_ERROR(XPATH_INVALID_OPERAND);
4998 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004999 xmlXPathFreeObject(arg);
5000
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005001 CAST_TO_NUMBER;
5002 CHECK_TYPE(XPATH_NUMBER);
5003 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005004}
5005
5006/**
5007 * xmlXPathDivValues:
5008 * @ctxt: the XPath Parser context
5009 *
5010 * Implement the div operation on XPath objects @arg1 / @arg2:
5011 * The numeric operators convert their operands to numbers as if
5012 * by calling the number function.
5013 */
5014void
5015xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
5016 xmlXPathObjectPtr arg;
5017 double val;
5018
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005019 arg = valuePop(ctxt);
5020 if (arg == NULL)
5021 XP_ERROR(XPATH_INVALID_OPERAND);
5022 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005023 xmlXPathFreeObject(arg);
5024
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005025 CAST_TO_NUMBER;
5026 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005027 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
5028 ctxt->value->floatval = xmlXPathNAN;
5029 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005030 if (ctxt->value->floatval == 0)
5031 ctxt->value->floatval = xmlXPathNAN;
5032 else if (ctxt->value->floatval > 0)
5033 ctxt->value->floatval = xmlXPathNINF;
5034 else if (ctxt->value->floatval < 0)
5035 ctxt->value->floatval = xmlXPathPINF;
5036 }
5037 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00005038 if (ctxt->value->floatval == 0)
5039 ctxt->value->floatval = xmlXPathNAN;
5040 else if (ctxt->value->floatval > 0)
5041 ctxt->value->floatval = xmlXPathPINF;
5042 else if (ctxt->value->floatval < 0)
5043 ctxt->value->floatval = xmlXPathNINF;
5044 } else
5045 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005046}
5047
5048/**
5049 * xmlXPathModValues:
5050 * @ctxt: the XPath Parser context
5051 *
5052 * Implement the mod operation on XPath objects: @arg1 / @arg2
5053 * The numeric operators convert their operands to numbers as if
5054 * by calling the number function.
5055 */
5056void
5057xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
5058 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005059 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00005060
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005061 arg = valuePop(ctxt);
5062 if (arg == NULL)
5063 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005064 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005065 xmlXPathFreeObject(arg);
5066
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005067 CAST_TO_NUMBER;
5068 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005069 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00005070 if (arg2 == 0)
5071 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005072 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00005073 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005074 }
Owen Taylor3473f882001-02-23 17:55:21 +00005075}
5076
5077/************************************************************************
5078 * *
5079 * The traversal functions *
5080 * *
5081 ************************************************************************/
5082
Owen Taylor3473f882001-02-23 17:55:21 +00005083/*
5084 * A traversal function enumerates nodes along an axis.
5085 * Initially it must be called with NULL, and it indicates
5086 * termination on the axis by returning NULL.
5087 */
5088typedef xmlNodePtr (*xmlXPathTraversalFunction)
5089 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
5090
5091/**
5092 * xmlXPathNextSelf:
5093 * @ctxt: the XPath Parser context
5094 * @cur: the current node in the traversal
5095 *
5096 * Traversal function for the "self" direction
5097 * The self axis contains just the context node itself
5098 *
5099 * Returns the next element following that axis
5100 */
5101xmlNodePtr
5102xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5103 if (cur == NULL)
5104 return(ctxt->context->node);
5105 return(NULL);
5106}
5107
5108/**
5109 * xmlXPathNextChild:
5110 * @ctxt: the XPath Parser context
5111 * @cur: the current node in the traversal
5112 *
5113 * Traversal function for the "child" direction
5114 * The child axis contains the children of the context node in document order.
5115 *
5116 * Returns the next element following that axis
5117 */
5118xmlNodePtr
5119xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5120 if (cur == NULL) {
5121 if (ctxt->context->node == NULL) return(NULL);
5122 switch (ctxt->context->node->type) {
5123 case XML_ELEMENT_NODE:
5124 case XML_TEXT_NODE:
5125 case XML_CDATA_SECTION_NODE:
5126 case XML_ENTITY_REF_NODE:
5127 case XML_ENTITY_NODE:
5128 case XML_PI_NODE:
5129 case XML_COMMENT_NODE:
5130 case XML_NOTATION_NODE:
5131 case XML_DTD_NODE:
5132 return(ctxt->context->node->children);
5133 case XML_DOCUMENT_NODE:
5134 case XML_DOCUMENT_TYPE_NODE:
5135 case XML_DOCUMENT_FRAG_NODE:
5136 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005137#ifdef LIBXML_DOCB_ENABLED
5138 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005139#endif
5140 return(((xmlDocPtr) ctxt->context->node)->children);
5141 case XML_ELEMENT_DECL:
5142 case XML_ATTRIBUTE_DECL:
5143 case XML_ENTITY_DECL:
5144 case XML_ATTRIBUTE_NODE:
5145 case XML_NAMESPACE_DECL:
5146 case XML_XINCLUDE_START:
5147 case XML_XINCLUDE_END:
5148 return(NULL);
5149 }
5150 return(NULL);
5151 }
5152 if ((cur->type == XML_DOCUMENT_NODE) ||
5153 (cur->type == XML_HTML_DOCUMENT_NODE))
5154 return(NULL);
5155 return(cur->next);
5156}
5157
5158/**
5159 * xmlXPathNextDescendant:
5160 * @ctxt: the XPath Parser context
5161 * @cur: the current node in the traversal
5162 *
5163 * Traversal function for the "descendant" direction
5164 * the descendant axis contains the descendants of the context node in document
5165 * order; a descendant is a child or a child of a child and so on.
5166 *
5167 * Returns the next element following that axis
5168 */
5169xmlNodePtr
5170xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5171 if (cur == NULL) {
5172 if (ctxt->context->node == NULL)
5173 return(NULL);
5174 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5175 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5176 return(NULL);
5177
5178 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5179 return(ctxt->context->doc->children);
5180 return(ctxt->context->node->children);
5181 }
5182
Daniel Veillard567e1b42001-08-01 15:53:47 +00005183 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00005184 /*
5185 * Do not descend on entities declarations
5186 */
5187 if (cur->children->type != XML_ENTITY_DECL) {
5188 cur = cur->children;
5189 /*
5190 * Skip DTDs
5191 */
5192 if (cur->type != XML_DTD_NODE)
5193 return(cur);
5194 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00005195 }
5196
5197 if (cur == ctxt->context->node) return(NULL);
5198
Daniel Veillard68e9e742002-11-16 15:35:11 +00005199 while (cur->next != NULL) {
5200 cur = cur->next;
5201 if ((cur->type != XML_ENTITY_DECL) &&
5202 (cur->type != XML_DTD_NODE))
5203 return(cur);
5204 }
Owen Taylor3473f882001-02-23 17:55:21 +00005205
5206 do {
5207 cur = cur->parent;
5208 if (cur == NULL) return(NULL);
5209 if (cur == ctxt->context->node) return(NULL);
5210 if (cur->next != NULL) {
5211 cur = cur->next;
5212 return(cur);
5213 }
5214 } while (cur != NULL);
5215 return(cur);
5216}
5217
5218/**
5219 * xmlXPathNextDescendantOrSelf:
5220 * @ctxt: the XPath Parser context
5221 * @cur: the current node in the traversal
5222 *
5223 * Traversal function for the "descendant-or-self" direction
5224 * the descendant-or-self axis contains the context node and the descendants
5225 * of the context node in document order; thus the context node is the first
5226 * node on the axis, and the first child of the context node is the second node
5227 * on the axis
5228 *
5229 * Returns the next element following that axis
5230 */
5231xmlNodePtr
5232xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5233 if (cur == NULL) {
5234 if (ctxt->context->node == NULL)
5235 return(NULL);
5236 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5237 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5238 return(NULL);
5239 return(ctxt->context->node);
5240 }
5241
5242 return(xmlXPathNextDescendant(ctxt, cur));
5243}
5244
5245/**
5246 * xmlXPathNextParent:
5247 * @ctxt: the XPath Parser context
5248 * @cur: the current node in the traversal
5249 *
5250 * Traversal function for the "parent" direction
5251 * The parent axis contains the parent of the context node, if there is one.
5252 *
5253 * Returns the next element following that axis
5254 */
5255xmlNodePtr
5256xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5257 /*
5258 * the parent of an attribute or namespace node is the element
5259 * to which the attribute or namespace node is attached
5260 * Namespace handling !!!
5261 */
5262 if (cur == NULL) {
5263 if (ctxt->context->node == NULL) return(NULL);
5264 switch (ctxt->context->node->type) {
5265 case XML_ELEMENT_NODE:
5266 case XML_TEXT_NODE:
5267 case XML_CDATA_SECTION_NODE:
5268 case XML_ENTITY_REF_NODE:
5269 case XML_ENTITY_NODE:
5270 case XML_PI_NODE:
5271 case XML_COMMENT_NODE:
5272 case XML_NOTATION_NODE:
5273 case XML_DTD_NODE:
5274 case XML_ELEMENT_DECL:
5275 case XML_ATTRIBUTE_DECL:
5276 case XML_XINCLUDE_START:
5277 case XML_XINCLUDE_END:
5278 case XML_ENTITY_DECL:
5279 if (ctxt->context->node->parent == NULL)
5280 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005281 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005282 ((ctxt->context->node->parent->name[0] == ' ') ||
5283 (xmlStrEqual(ctxt->context->node->parent->name,
5284 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005285 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005286 return(ctxt->context->node->parent);
5287 case XML_ATTRIBUTE_NODE: {
5288 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5289
5290 return(att->parent);
5291 }
5292 case XML_DOCUMENT_NODE:
5293 case XML_DOCUMENT_TYPE_NODE:
5294 case XML_DOCUMENT_FRAG_NODE:
5295 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005296#ifdef LIBXML_DOCB_ENABLED
5297 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005298#endif
5299 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005300 case XML_NAMESPACE_DECL: {
5301 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5302
5303 if ((ns->next != NULL) &&
5304 (ns->next->type != XML_NAMESPACE_DECL))
5305 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005306 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005307 }
Owen Taylor3473f882001-02-23 17:55:21 +00005308 }
5309 }
5310 return(NULL);
5311}
5312
5313/**
5314 * xmlXPathNextAncestor:
5315 * @ctxt: the XPath Parser context
5316 * @cur: the current node in the traversal
5317 *
5318 * Traversal function for the "ancestor" direction
5319 * the ancestor axis contains the ancestors of the context node; the ancestors
5320 * of the context node consist of the parent of context node and the parent's
5321 * parent and so on; the nodes are ordered in reverse document order; thus the
5322 * parent is the first node on the axis, and the parent's parent is the second
5323 * node on the axis
5324 *
5325 * Returns the next element following that axis
5326 */
5327xmlNodePtr
5328xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5329 /*
5330 * the parent of an attribute or namespace node is the element
5331 * to which the attribute or namespace node is attached
5332 * !!!!!!!!!!!!!
5333 */
5334 if (cur == NULL) {
5335 if (ctxt->context->node == NULL) return(NULL);
5336 switch (ctxt->context->node->type) {
5337 case XML_ELEMENT_NODE:
5338 case XML_TEXT_NODE:
5339 case XML_CDATA_SECTION_NODE:
5340 case XML_ENTITY_REF_NODE:
5341 case XML_ENTITY_NODE:
5342 case XML_PI_NODE:
5343 case XML_COMMENT_NODE:
5344 case XML_DTD_NODE:
5345 case XML_ELEMENT_DECL:
5346 case XML_ATTRIBUTE_DECL:
5347 case XML_ENTITY_DECL:
5348 case XML_NOTATION_NODE:
5349 case XML_XINCLUDE_START:
5350 case XML_XINCLUDE_END:
5351 if (ctxt->context->node->parent == NULL)
5352 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005353 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005354 ((ctxt->context->node->parent->name[0] == ' ') ||
5355 (xmlStrEqual(ctxt->context->node->parent->name,
5356 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005357 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005358 return(ctxt->context->node->parent);
5359 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005360 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005361
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005362 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005363 }
5364 case XML_DOCUMENT_NODE:
5365 case XML_DOCUMENT_TYPE_NODE:
5366 case XML_DOCUMENT_FRAG_NODE:
5367 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005368#ifdef LIBXML_DOCB_ENABLED
5369 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005370#endif
5371 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005372 case XML_NAMESPACE_DECL: {
5373 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5374
5375 if ((ns->next != NULL) &&
5376 (ns->next->type != XML_NAMESPACE_DECL))
5377 return((xmlNodePtr) ns->next);
5378 /* Bad, how did that namespace ended-up there ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005379 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005380 }
Owen Taylor3473f882001-02-23 17:55:21 +00005381 }
5382 return(NULL);
5383 }
5384 if (cur == ctxt->context->doc->children)
5385 return((xmlNodePtr) ctxt->context->doc);
5386 if (cur == (xmlNodePtr) ctxt->context->doc)
5387 return(NULL);
5388 switch (cur->type) {
5389 case XML_ELEMENT_NODE:
5390 case XML_TEXT_NODE:
5391 case XML_CDATA_SECTION_NODE:
5392 case XML_ENTITY_REF_NODE:
5393 case XML_ENTITY_NODE:
5394 case XML_PI_NODE:
5395 case XML_COMMENT_NODE:
5396 case XML_NOTATION_NODE:
5397 case XML_DTD_NODE:
5398 case XML_ELEMENT_DECL:
5399 case XML_ATTRIBUTE_DECL:
5400 case XML_ENTITY_DECL:
5401 case XML_XINCLUDE_START:
5402 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005403 if (cur->parent == NULL)
5404 return(NULL);
5405 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005406 ((cur->parent->name[0] == ' ') ||
5407 (xmlStrEqual(cur->parent->name,
5408 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005409 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005410 return(cur->parent);
5411 case XML_ATTRIBUTE_NODE: {
5412 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5413
5414 return(att->parent);
5415 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005416 case XML_NAMESPACE_DECL: {
5417 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5418
5419 if ((ns->next != NULL) &&
5420 (ns->next->type != XML_NAMESPACE_DECL))
5421 return((xmlNodePtr) ns->next);
5422 /* Bad, how did that namespace ended-up there ? */
5423 return(NULL);
5424 }
Owen Taylor3473f882001-02-23 17:55:21 +00005425 case XML_DOCUMENT_NODE:
5426 case XML_DOCUMENT_TYPE_NODE:
5427 case XML_DOCUMENT_FRAG_NODE:
5428 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005429#ifdef LIBXML_DOCB_ENABLED
5430 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005431#endif
5432 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005433 }
5434 return(NULL);
5435}
5436
5437/**
5438 * xmlXPathNextAncestorOrSelf:
5439 * @ctxt: the XPath Parser context
5440 * @cur: the current node in the traversal
5441 *
5442 * Traversal function for the "ancestor-or-self" direction
5443 * he ancestor-or-self axis contains the context node and ancestors of
5444 * the context node in reverse document order; thus the context node is
5445 * the first node on the axis, and the context node's parent the second;
5446 * parent here is defined the same as with the parent axis.
5447 *
5448 * Returns the next element following that axis
5449 */
5450xmlNodePtr
5451xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5452 if (cur == NULL)
5453 return(ctxt->context->node);
5454 return(xmlXPathNextAncestor(ctxt, cur));
5455}
5456
5457/**
5458 * xmlXPathNextFollowingSibling:
5459 * @ctxt: the XPath Parser context
5460 * @cur: the current node in the traversal
5461 *
5462 * Traversal function for the "following-sibling" direction
5463 * The following-sibling axis contains the following siblings of the context
5464 * node in document order.
5465 *
5466 * Returns the next element following that axis
5467 */
5468xmlNodePtr
5469xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5470 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5471 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5472 return(NULL);
5473 if (cur == (xmlNodePtr) ctxt->context->doc)
5474 return(NULL);
5475 if (cur == NULL)
5476 return(ctxt->context->node->next);
5477 return(cur->next);
5478}
5479
5480/**
5481 * xmlXPathNextPrecedingSibling:
5482 * @ctxt: the XPath Parser context
5483 * @cur: the current node in the traversal
5484 *
5485 * Traversal function for the "preceding-sibling" direction
5486 * The preceding-sibling axis contains the preceding siblings of the context
5487 * node in reverse document order; the first preceding sibling is first on the
5488 * axis; the sibling preceding that node is the second on the axis and so on.
5489 *
5490 * Returns the next element following that axis
5491 */
5492xmlNodePtr
5493xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5494 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5495 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5496 return(NULL);
5497 if (cur == (xmlNodePtr) ctxt->context->doc)
5498 return(NULL);
5499 if (cur == NULL)
5500 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005501 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5502 cur = cur->prev;
5503 if (cur == NULL)
5504 return(ctxt->context->node->prev);
5505 }
Owen Taylor3473f882001-02-23 17:55:21 +00005506 return(cur->prev);
5507}
5508
5509/**
5510 * xmlXPathNextFollowing:
5511 * @ctxt: the XPath Parser context
5512 * @cur: the current node in the traversal
5513 *
5514 * Traversal function for the "following" direction
5515 * The following axis contains all nodes in the same document as the context
5516 * node that are after the context node in document order, excluding any
5517 * descendants and excluding attribute nodes and namespace nodes; the nodes
5518 * are ordered in document order
5519 *
5520 * Returns the next element following that axis
5521 */
5522xmlNodePtr
5523xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5524 if (cur != NULL && cur->children != NULL)
5525 return cur->children ;
5526 if (cur == NULL) cur = ctxt->context->node;
5527 if (cur == NULL) return(NULL) ; /* ERROR */
5528 if (cur->next != NULL) return(cur->next) ;
5529 do {
5530 cur = cur->parent;
5531 if (cur == NULL) return(NULL);
5532 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5533 if (cur->next != NULL) return(cur->next);
5534 } while (cur != NULL);
5535 return(cur);
5536}
5537
5538/*
5539 * xmlXPathIsAncestor:
5540 * @ancestor: the ancestor node
5541 * @node: the current node
5542 *
5543 * Check that @ancestor is a @node's ancestor
5544 *
5545 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5546 */
5547static int
5548xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5549 if ((ancestor == NULL) || (node == NULL)) return(0);
5550 /* nodes need to be in the same document */
5551 if (ancestor->doc != node->doc) return(0);
5552 /* avoid searching if ancestor or node is the root node */
5553 if (ancestor == (xmlNodePtr) node->doc) return(1);
5554 if (node == (xmlNodePtr) ancestor->doc) return(0);
5555 while (node->parent != NULL) {
5556 if (node->parent == ancestor)
5557 return(1);
5558 node = node->parent;
5559 }
5560 return(0);
5561}
5562
5563/**
5564 * xmlXPathNextPreceding:
5565 * @ctxt: the XPath Parser context
5566 * @cur: the current node in the traversal
5567 *
5568 * Traversal function for the "preceding" direction
5569 * the preceding axis contains all nodes in the same document as the context
5570 * node that are before the context node in document order, excluding any
5571 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5572 * ordered in reverse document order
5573 *
5574 * Returns the next element following that axis
5575 */
5576xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005577xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5578{
Owen Taylor3473f882001-02-23 17:55:21 +00005579 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005580 cur = ctxt->context->node;
5581 if (cur == NULL)
5582 return (NULL);
5583 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5584 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005585 do {
5586 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005587 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5588 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005589 }
5590
5591 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005592 if (cur == NULL)
5593 return (NULL);
5594 if (cur == ctxt->context->doc->children)
5595 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005596 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005597 return (cur);
5598}
5599
5600/**
5601 * xmlXPathNextPrecedingInternal:
5602 * @ctxt: the XPath Parser context
5603 * @cur: the current node in the traversal
5604 *
5605 * Traversal function for the "preceding" direction
5606 * the preceding axis contains all nodes in the same document as the context
5607 * node that are before the context node in document order, excluding any
5608 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5609 * ordered in reverse document order
5610 * This is a faster implementation but internal only since it requires a
5611 * state kept in the parser context: ctxt->ancestor.
5612 *
5613 * Returns the next element following that axis
5614 */
5615static xmlNodePtr
5616xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5617 xmlNodePtr cur)
5618{
5619 if (cur == NULL) {
5620 cur = ctxt->context->node;
5621 if (cur == NULL)
5622 return (NULL);
5623 ctxt->ancestor = cur->parent;
5624 }
5625 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5626 cur = cur->prev;
5627 while (cur->prev == NULL) {
5628 cur = cur->parent;
5629 if (cur == NULL)
5630 return (NULL);
5631 if (cur == ctxt->context->doc->children)
5632 return (NULL);
5633 if (cur != ctxt->ancestor)
5634 return (cur);
5635 ctxt->ancestor = cur->parent;
5636 }
5637 cur = cur->prev;
5638 while (cur->last != NULL)
5639 cur = cur->last;
5640 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005641}
5642
5643/**
5644 * xmlXPathNextNamespace:
5645 * @ctxt: the XPath Parser context
5646 * @cur: the current attribute in the traversal
5647 *
5648 * Traversal function for the "namespace" direction
5649 * the namespace axis contains the namespace nodes of the context node;
5650 * the order of nodes on this axis is implementation-defined; the axis will
5651 * be empty unless the context node is an element
5652 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005653 * We keep the XML namespace node at the end of the list.
5654 *
Owen Taylor3473f882001-02-23 17:55:21 +00005655 * Returns the next element following that axis
5656 */
5657xmlNodePtr
5658xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5659 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00005660 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005661 if (ctxt->context->tmpNsList != NULL)
5662 xmlFree(ctxt->context->tmpNsList);
5663 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005664 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005665 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005666 if (ctxt->context->tmpNsList != NULL) {
5667 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
5668 ctxt->context->tmpNsNr++;
5669 }
5670 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005671 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005672 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00005673 if (ctxt->context->tmpNsNr > 0) {
5674 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
5675 } else {
5676 if (ctxt->context->tmpNsList != NULL)
5677 xmlFree(ctxt->context->tmpNsList);
5678 ctxt->context->tmpNsList = NULL;
5679 return(NULL);
5680 }
Owen Taylor3473f882001-02-23 17:55:21 +00005681}
5682
5683/**
5684 * xmlXPathNextAttribute:
5685 * @ctxt: the XPath Parser context
5686 * @cur: the current attribute in the traversal
5687 *
5688 * Traversal function for the "attribute" direction
5689 * TODO: support DTD inherited default attributes
5690 *
5691 * Returns the next element following that axis
5692 */
5693xmlNodePtr
5694xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005695 if (ctxt->context->node == NULL)
5696 return(NULL);
5697 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5698 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005699 if (cur == NULL) {
5700 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5701 return(NULL);
5702 return((xmlNodePtr)ctxt->context->node->properties);
5703 }
5704 return((xmlNodePtr)cur->next);
5705}
5706
5707/************************************************************************
5708 * *
5709 * NodeTest Functions *
5710 * *
5711 ************************************************************************/
5712
Owen Taylor3473f882001-02-23 17:55:21 +00005713#define IS_FUNCTION 200
5714
Owen Taylor3473f882001-02-23 17:55:21 +00005715
5716/************************************************************************
5717 * *
5718 * Implicit tree core function library *
5719 * *
5720 ************************************************************************/
5721
5722/**
5723 * xmlXPathRoot:
5724 * @ctxt: the XPath Parser context
5725 *
5726 * Initialize the context to the root of the document
5727 */
5728void
5729xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5730 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5731 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5732}
5733
5734/************************************************************************
5735 * *
5736 * The explicit core function library *
5737 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5738 * *
5739 ************************************************************************/
5740
5741
5742/**
5743 * xmlXPathLastFunction:
5744 * @ctxt: the XPath Parser context
5745 * @nargs: the number of arguments
5746 *
5747 * Implement the last() XPath function
5748 * number last()
5749 * The last function returns the number of nodes in the context node list.
5750 */
5751void
5752xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5753 CHECK_ARITY(0);
5754 if (ctxt->context->contextSize >= 0) {
5755 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5756#ifdef DEBUG_EXPR
5757 xmlGenericError(xmlGenericErrorContext,
5758 "last() : %d\n", ctxt->context->contextSize);
5759#endif
5760 } else {
5761 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5762 }
5763}
5764
5765/**
5766 * xmlXPathPositionFunction:
5767 * @ctxt: the XPath Parser context
5768 * @nargs: the number of arguments
5769 *
5770 * Implement the position() XPath function
5771 * number position()
5772 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005773 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00005774 * will be equal to last().
5775 */
5776void
5777xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5778 CHECK_ARITY(0);
5779 if (ctxt->context->proximityPosition >= 0) {
5780 valuePush(ctxt,
5781 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5782#ifdef DEBUG_EXPR
5783 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5784 ctxt->context->proximityPosition);
5785#endif
5786 } else {
5787 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5788 }
5789}
5790
5791/**
5792 * xmlXPathCountFunction:
5793 * @ctxt: the XPath Parser context
5794 * @nargs: the number of arguments
5795 *
5796 * Implement the count() XPath function
5797 * number count(node-set)
5798 */
5799void
5800xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5801 xmlXPathObjectPtr cur;
5802
5803 CHECK_ARITY(1);
5804 if ((ctxt->value == NULL) ||
5805 ((ctxt->value->type != XPATH_NODESET) &&
5806 (ctxt->value->type != XPATH_XSLT_TREE)))
5807 XP_ERROR(XPATH_INVALID_TYPE);
5808 cur = valuePop(ctxt);
5809
Daniel Veillard911f49a2001-04-07 15:39:35 +00005810 if ((cur == NULL) || (cur->nodesetval == NULL))
5811 valuePush(ctxt, xmlXPathNewFloat((double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00005812 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00005813 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00005814 } else {
5815 if ((cur->nodesetval->nodeNr != 1) ||
5816 (cur->nodesetval->nodeTab == NULL)) {
5817 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5818 } else {
5819 xmlNodePtr tmp;
5820 int i = 0;
5821
5822 tmp = cur->nodesetval->nodeTab[0];
5823 if (tmp != NULL) {
5824 tmp = tmp->children;
5825 while (tmp != NULL) {
5826 tmp = tmp->next;
5827 i++;
5828 }
5829 }
5830 valuePush(ctxt, xmlXPathNewFloat((double) i));
5831 }
5832 }
Owen Taylor3473f882001-02-23 17:55:21 +00005833 xmlXPathFreeObject(cur);
5834}
5835
5836/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005837 * xmlXPathGetElementsByIds:
5838 * @doc: the document
5839 * @ids: a whitespace separated list of IDs
5840 *
5841 * Selects elements by their unique ID.
5842 *
5843 * Returns a node-set of selected elements.
5844 */
5845static xmlNodeSetPtr
5846xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5847 xmlNodeSetPtr ret;
5848 const xmlChar *cur = ids;
5849 xmlChar *ID;
5850 xmlAttrPtr attr;
5851 xmlNodePtr elem = NULL;
5852
5853 ret = xmlXPathNodeSetCreate(NULL);
5854
5855 while (IS_BLANK(*cur)) cur++;
5856 while (*cur != 0) {
5857 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
5858 (*cur == '.') || (*cur == '-') ||
5859 (*cur == '_') || (*cur == ':') ||
5860 (IS_COMBINING(*cur)) ||
5861 (IS_EXTENDER(*cur)))
5862 cur++;
5863
5864 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
5865
5866 ID = xmlStrndup(ids, cur - ids);
5867 attr = xmlGetID(doc, ID);
5868 if (attr != NULL) {
5869 elem = attr->parent;
5870 xmlXPathNodeSetAdd(ret, elem);
5871 }
5872 if (ID != NULL)
5873 xmlFree(ID);
5874
5875 while (IS_BLANK(*cur)) cur++;
5876 ids = cur;
5877 }
5878 return(ret);
5879}
5880
5881/**
Owen Taylor3473f882001-02-23 17:55:21 +00005882 * xmlXPathIdFunction:
5883 * @ctxt: the XPath Parser context
5884 * @nargs: the number of arguments
5885 *
5886 * Implement the id() XPath function
5887 * node-set id(object)
5888 * The id function selects elements by their unique ID
5889 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
5890 * then the result is the union of the result of applying id to the
5891 * string value of each of the nodes in the argument node-set. When the
5892 * argument to id is of any other type, the argument is converted to a
5893 * string as if by a call to the string function; the string is split
5894 * into a whitespace-separated list of tokens (whitespace is any sequence
5895 * of characters matching the production S); the result is a node-set
5896 * containing the elements in the same document as the context node that
5897 * have a unique ID equal to any of the tokens in the list.
5898 */
5899void
5900xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005901 xmlChar *tokens;
5902 xmlNodeSetPtr ret;
5903 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00005904
5905 CHECK_ARITY(1);
5906 obj = valuePop(ctxt);
5907 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00005908 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005909 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00005910 int i;
5911
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005912 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005913
Daniel Veillard911f49a2001-04-07 15:39:35 +00005914 if (obj->nodesetval != NULL) {
5915 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005916 tokens =
5917 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
5918 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
5919 ret = xmlXPathNodeSetMerge(ret, ns);
5920 xmlXPathFreeNodeSet(ns);
5921 if (tokens != NULL)
5922 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00005923 }
Owen Taylor3473f882001-02-23 17:55:21 +00005924 }
5925
5926 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005927 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005928 return;
5929 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005930 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00005931
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005932 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
5933 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005934
Owen Taylor3473f882001-02-23 17:55:21 +00005935 xmlXPathFreeObject(obj);
5936 return;
5937}
5938
5939/**
5940 * xmlXPathLocalNameFunction:
5941 * @ctxt: the XPath Parser context
5942 * @nargs: the number of arguments
5943 *
5944 * Implement the local-name() XPath function
5945 * string local-name(node-set?)
5946 * The local-name function returns a string containing the local part
5947 * of the name of the node in the argument node-set that is first in
5948 * document order. If the node-set is empty or the first node has no
5949 * name, an empty string is returned. If the argument is omitted it
5950 * defaults to the context node.
5951 */
5952void
5953xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5954 xmlXPathObjectPtr cur;
5955
5956 if (nargs == 0) {
5957 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5958 nargs = 1;
5959 }
5960
5961 CHECK_ARITY(1);
5962 if ((ctxt->value == NULL) ||
5963 ((ctxt->value->type != XPATH_NODESET) &&
5964 (ctxt->value->type != XPATH_XSLT_TREE)))
5965 XP_ERROR(XPATH_INVALID_TYPE);
5966 cur = valuePop(ctxt);
5967
Daniel Veillard911f49a2001-04-07 15:39:35 +00005968 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005969 valuePush(ctxt, xmlXPathNewCString(""));
5970 } else {
5971 int i = 0; /* Should be first in document order !!!!! */
5972 switch (cur->nodesetval->nodeTab[i]->type) {
5973 case XML_ELEMENT_NODE:
5974 case XML_ATTRIBUTE_NODE:
5975 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00005976 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
5977 valuePush(ctxt, xmlXPathNewCString(""));
5978 else
5979 valuePush(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00005980 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
5981 break;
5982 case XML_NAMESPACE_DECL:
5983 valuePush(ctxt, xmlXPathNewString(
5984 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
5985 break;
5986 default:
5987 valuePush(ctxt, xmlXPathNewCString(""));
5988 }
5989 }
5990 xmlXPathFreeObject(cur);
5991}
5992
5993/**
5994 * xmlXPathNamespaceURIFunction:
5995 * @ctxt: the XPath Parser context
5996 * @nargs: the number of arguments
5997 *
5998 * Implement the namespace-uri() XPath function
5999 * string namespace-uri(node-set?)
6000 * The namespace-uri function returns a string containing the
6001 * namespace URI of the expanded name of the node in the argument
6002 * node-set that is first in document order. If the node-set is empty,
6003 * the first node has no name, or the expanded name has no namespace
6004 * URI, an empty string is returned. If the argument is omitted it
6005 * defaults to the context node.
6006 */
6007void
6008xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6009 xmlXPathObjectPtr cur;
6010
6011 if (nargs == 0) {
6012 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6013 nargs = 1;
6014 }
6015 CHECK_ARITY(1);
6016 if ((ctxt->value == NULL) ||
6017 ((ctxt->value->type != XPATH_NODESET) &&
6018 (ctxt->value->type != XPATH_XSLT_TREE)))
6019 XP_ERROR(XPATH_INVALID_TYPE);
6020 cur = valuePop(ctxt);
6021
Daniel Veillard911f49a2001-04-07 15:39:35 +00006022 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006023 valuePush(ctxt, xmlXPathNewCString(""));
6024 } else {
6025 int i = 0; /* Should be first in document order !!!!! */
6026 switch (cur->nodesetval->nodeTab[i]->type) {
6027 case XML_ELEMENT_NODE:
6028 case XML_ATTRIBUTE_NODE:
6029 if (cur->nodesetval->nodeTab[i]->ns == NULL)
6030 valuePush(ctxt, xmlXPathNewCString(""));
6031 else
6032 valuePush(ctxt, xmlXPathNewString(
6033 cur->nodesetval->nodeTab[i]->ns->href));
6034 break;
6035 default:
6036 valuePush(ctxt, xmlXPathNewCString(""));
6037 }
6038 }
6039 xmlXPathFreeObject(cur);
6040}
6041
6042/**
6043 * xmlXPathNameFunction:
6044 * @ctxt: the XPath Parser context
6045 * @nargs: the number of arguments
6046 *
6047 * Implement the name() XPath function
6048 * string name(node-set?)
6049 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006050 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00006051 * order. The QName must represent the name with respect to the namespace
6052 * declarations in effect on the node whose name is being represented.
6053 * Typically, this will be the form in which the name occurred in the XML
6054 * source. This need not be the case if there are namespace declarations
6055 * in effect on the node that associate multiple prefixes with the same
6056 * namespace. However, an implementation may include information about
6057 * the original prefix in its representation of nodes; in this case, an
6058 * implementation can ensure that the returned string is always the same
6059 * as the QName used in the XML source. If the argument it omitted it
6060 * defaults to the context node.
6061 * Libxml keep the original prefix so the "real qualified name" used is
6062 * returned.
6063 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006064static void
Daniel Veillard04383752001-07-08 14:27:15 +00006065xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
6066{
Owen Taylor3473f882001-02-23 17:55:21 +00006067 xmlXPathObjectPtr cur;
6068
6069 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00006070 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6071 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006072 }
6073
6074 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00006075 if ((ctxt->value == NULL) ||
6076 ((ctxt->value->type != XPATH_NODESET) &&
6077 (ctxt->value->type != XPATH_XSLT_TREE)))
6078 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006079 cur = valuePop(ctxt);
6080
Daniel Veillard911f49a2001-04-07 15:39:35 +00006081 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006082 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00006083 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006084 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00006085
Daniel Veillard04383752001-07-08 14:27:15 +00006086 switch (cur->nodesetval->nodeTab[i]->type) {
6087 case XML_ELEMENT_NODE:
6088 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006089 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6090 valuePush(ctxt, xmlXPathNewCString(""));
6091 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6092 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006093 valuePush(ctxt,
6094 xmlXPathNewString(cur->nodesetval->
6095 nodeTab[i]->name));
6096
Daniel Veillard652d8a92003-02-04 19:28:49 +00006097 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006098 char name[2000];
6099
6100 snprintf(name, sizeof(name), "%s:%s",
6101 (char *) cur->nodesetval->nodeTab[i]->ns->
6102 prefix,
6103 (char *) cur->nodesetval->nodeTab[i]->name);
6104 name[sizeof(name) - 1] = 0;
6105 valuePush(ctxt, xmlXPathNewCString(name));
6106 }
6107 break;
6108 default:
6109 valuePush(ctxt,
6110 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6111 xmlXPathLocalNameFunction(ctxt, 1);
6112 }
Owen Taylor3473f882001-02-23 17:55:21 +00006113 }
6114 xmlXPathFreeObject(cur);
6115}
6116
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006117
6118/**
Owen Taylor3473f882001-02-23 17:55:21 +00006119 * xmlXPathStringFunction:
6120 * @ctxt: the XPath Parser context
6121 * @nargs: the number of arguments
6122 *
6123 * Implement the string() XPath function
6124 * string string(object?)
6125 * he string function converts an object to a string as follows:
6126 * - A node-set is converted to a string by returning the value of
6127 * the node in the node-set that is first in document order.
6128 * If the node-set is empty, an empty string is returned.
6129 * - A number is converted to a string as follows
6130 * + NaN is converted to the string NaN
6131 * + positive zero is converted to the string 0
6132 * + negative zero is converted to the string 0
6133 * + positive infinity is converted to the string Infinity
6134 * + negative infinity is converted to the string -Infinity
6135 * + if the number is an integer, the number is represented in
6136 * decimal form as a Number with no decimal point and no leading
6137 * zeros, preceded by a minus sign (-) if the number is negative
6138 * + otherwise, the number is represented in decimal form as a
6139 * Number including a decimal point with at least one digit
6140 * before the decimal point and at least one digit after the
6141 * decimal point, preceded by a minus sign (-) if the number
6142 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006143 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00006144 * before the decimal point; beyond the one required digit
6145 * after the decimal point there must be as many, but only as
6146 * many, more digits as are needed to uniquely distinguish the
6147 * number from all other IEEE 754 numeric values.
6148 * - The boolean false value is converted to the string false.
6149 * The boolean true value is converted to the string true.
6150 *
6151 * If the argument is omitted, it defaults to a node-set with the
6152 * context node as its only member.
6153 */
6154void
6155xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6156 xmlXPathObjectPtr cur;
6157
6158 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006159 valuePush(ctxt,
6160 xmlXPathWrapString(
6161 xmlXPathCastNodeToString(ctxt->context->node)));
6162 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006163 }
6164
6165 CHECK_ARITY(1);
6166 cur = valuePop(ctxt);
6167 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006168 cur = xmlXPathConvertString(cur);
6169 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006170}
6171
6172/**
6173 * xmlXPathStringLengthFunction:
6174 * @ctxt: the XPath Parser context
6175 * @nargs: the number of arguments
6176 *
6177 * Implement the string-length() XPath function
6178 * number string-length(string?)
6179 * The string-length returns the number of characters in the string
6180 * (see [3.6 Strings]). If the argument is omitted, it defaults to
6181 * the context node converted to a string, in other words the value
6182 * of the context node.
6183 */
6184void
6185xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6186 xmlXPathObjectPtr cur;
6187
6188 if (nargs == 0) {
6189 if (ctxt->context->node == NULL) {
6190 valuePush(ctxt, xmlXPathNewFloat(0));
6191 } else {
6192 xmlChar *content;
6193
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006194 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006195 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00006196 xmlFree(content);
6197 }
6198 return;
6199 }
6200 CHECK_ARITY(1);
6201 CAST_TO_STRING;
6202 CHECK_TYPE(XPATH_STRING);
6203 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006204 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00006205 xmlXPathFreeObject(cur);
6206}
6207
6208/**
6209 * xmlXPathConcatFunction:
6210 * @ctxt: the XPath Parser context
6211 * @nargs: the number of arguments
6212 *
6213 * Implement the concat() XPath function
6214 * string concat(string, string, string*)
6215 * The concat function returns the concatenation of its arguments.
6216 */
6217void
6218xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6219 xmlXPathObjectPtr cur, newobj;
6220 xmlChar *tmp;
6221
6222 if (nargs < 2) {
6223 CHECK_ARITY(2);
6224 }
6225
6226 CAST_TO_STRING;
6227 cur = valuePop(ctxt);
6228 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6229 xmlXPathFreeObject(cur);
6230 return;
6231 }
6232 nargs--;
6233
6234 while (nargs > 0) {
6235 CAST_TO_STRING;
6236 newobj = valuePop(ctxt);
6237 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6238 xmlXPathFreeObject(newobj);
6239 xmlXPathFreeObject(cur);
6240 XP_ERROR(XPATH_INVALID_TYPE);
6241 }
6242 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6243 newobj->stringval = cur->stringval;
6244 cur->stringval = tmp;
6245
6246 xmlXPathFreeObject(newobj);
6247 nargs--;
6248 }
6249 valuePush(ctxt, cur);
6250}
6251
6252/**
6253 * xmlXPathContainsFunction:
6254 * @ctxt: the XPath Parser context
6255 * @nargs: the number of arguments
6256 *
6257 * Implement the contains() XPath function
6258 * boolean contains(string, string)
6259 * The contains function returns true if the first argument string
6260 * contains the second argument string, and otherwise returns false.
6261 */
6262void
6263xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6264 xmlXPathObjectPtr hay, needle;
6265
6266 CHECK_ARITY(2);
6267 CAST_TO_STRING;
6268 CHECK_TYPE(XPATH_STRING);
6269 needle = valuePop(ctxt);
6270 CAST_TO_STRING;
6271 hay = valuePop(ctxt);
6272 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6273 xmlXPathFreeObject(hay);
6274 xmlXPathFreeObject(needle);
6275 XP_ERROR(XPATH_INVALID_TYPE);
6276 }
6277 if (xmlStrstr(hay->stringval, needle->stringval))
6278 valuePush(ctxt, xmlXPathNewBoolean(1));
6279 else
6280 valuePush(ctxt, xmlXPathNewBoolean(0));
6281 xmlXPathFreeObject(hay);
6282 xmlXPathFreeObject(needle);
6283}
6284
6285/**
6286 * xmlXPathStartsWithFunction:
6287 * @ctxt: the XPath Parser context
6288 * @nargs: the number of arguments
6289 *
6290 * Implement the starts-with() XPath function
6291 * boolean starts-with(string, string)
6292 * The starts-with function returns true if the first argument string
6293 * starts with the second argument string, and otherwise returns false.
6294 */
6295void
6296xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6297 xmlXPathObjectPtr hay, needle;
6298 int n;
6299
6300 CHECK_ARITY(2);
6301 CAST_TO_STRING;
6302 CHECK_TYPE(XPATH_STRING);
6303 needle = valuePop(ctxt);
6304 CAST_TO_STRING;
6305 hay = valuePop(ctxt);
6306 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6307 xmlXPathFreeObject(hay);
6308 xmlXPathFreeObject(needle);
6309 XP_ERROR(XPATH_INVALID_TYPE);
6310 }
6311 n = xmlStrlen(needle->stringval);
6312 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6313 valuePush(ctxt, xmlXPathNewBoolean(0));
6314 else
6315 valuePush(ctxt, xmlXPathNewBoolean(1));
6316 xmlXPathFreeObject(hay);
6317 xmlXPathFreeObject(needle);
6318}
6319
6320/**
6321 * xmlXPathSubstringFunction:
6322 * @ctxt: the XPath Parser context
6323 * @nargs: the number of arguments
6324 *
6325 * Implement the substring() XPath function
6326 * string substring(string, number, number?)
6327 * The substring function returns the substring of the first argument
6328 * starting at the position specified in the second argument with
6329 * length specified in the third argument. For example,
6330 * substring("12345",2,3) returns "234". If the third argument is not
6331 * specified, it returns the substring starting at the position specified
6332 * in the second argument and continuing to the end of the string. For
6333 * example, substring("12345",2) returns "2345". More precisely, each
6334 * character in the string (see [3.6 Strings]) is considered to have a
6335 * numeric position: the position of the first character is 1, the position
6336 * of the second character is 2 and so on. The returned substring contains
6337 * those characters for which the position of the character is greater than
6338 * or equal to the second argument and, if the third argument is specified,
6339 * less than the sum of the second and third arguments; the comparisons
6340 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6341 * - substring("12345", 1.5, 2.6) returns "234"
6342 * - substring("12345", 0, 3) returns "12"
6343 * - substring("12345", 0 div 0, 3) returns ""
6344 * - substring("12345", 1, 0 div 0) returns ""
6345 * - substring("12345", -42, 1 div 0) returns "12345"
6346 * - substring("12345", -1 div 0, 1 div 0) returns ""
6347 */
6348void
6349xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6350 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006351 double le=0, in;
6352 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006353 xmlChar *ret;
6354
Owen Taylor3473f882001-02-23 17:55:21 +00006355 if (nargs < 2) {
6356 CHECK_ARITY(2);
6357 }
6358 if (nargs > 3) {
6359 CHECK_ARITY(3);
6360 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006361 /*
6362 * take care of possible last (position) argument
6363 */
Owen Taylor3473f882001-02-23 17:55:21 +00006364 if (nargs == 3) {
6365 CAST_TO_NUMBER;
6366 CHECK_TYPE(XPATH_NUMBER);
6367 len = valuePop(ctxt);
6368 le = len->floatval;
6369 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006370 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006371
Owen Taylor3473f882001-02-23 17:55:21 +00006372 CAST_TO_NUMBER;
6373 CHECK_TYPE(XPATH_NUMBER);
6374 start = valuePop(ctxt);
6375 in = start->floatval;
6376 xmlXPathFreeObject(start);
6377 CAST_TO_STRING;
6378 CHECK_TYPE(XPATH_STRING);
6379 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006380 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006381
Daniel Veillard97ac1312001-05-30 19:14:17 +00006382 /*
6383 * If last pos not present, calculate last position
6384 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006385 if (nargs != 3) {
6386 le = (double)m;
6387 if (in < 1.0)
6388 in = 1.0;
6389 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006390
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006391 /* Need to check for the special cases where either
6392 * the index is NaN, the length is NaN, or both
6393 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00006394 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006395 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006396 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00006397 * To meet the requirements of the spec, the arguments
6398 * must be converted to integer format before
6399 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006400 *
Daniel Veillard9e412302002-06-10 15:59:44 +00006401 * First we go to integer form, rounding up
6402 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006403 */
6404 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00006405 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00006406
Daniel Veillard9e412302002-06-10 15:59:44 +00006407 if (xmlXPathIsInf(le) == 1) {
6408 l = m;
6409 if (i < 1)
6410 i = 1;
6411 }
6412 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
6413 l = 0;
6414 else {
6415 l = (int) le;
6416 if (((double)l)+0.5 <= le) l++;
6417 }
6418
6419 /* Now we normalize inidices */
6420 i -= 1;
6421 l += i;
6422 if (i < 0)
6423 i = 0;
6424 if (l > m)
6425 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00006426
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006427 /* number of chars to copy */
6428 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00006429
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006430 ret = xmlUTF8Strsub(str->stringval, i, l);
6431 }
6432 else {
6433 ret = NULL;
6434 }
6435
Owen Taylor3473f882001-02-23 17:55:21 +00006436 if (ret == NULL)
6437 valuePush(ctxt, xmlXPathNewCString(""));
6438 else {
6439 valuePush(ctxt, xmlXPathNewString(ret));
6440 xmlFree(ret);
6441 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006442
Owen Taylor3473f882001-02-23 17:55:21 +00006443 xmlXPathFreeObject(str);
6444}
6445
6446/**
6447 * xmlXPathSubstringBeforeFunction:
6448 * @ctxt: the XPath Parser context
6449 * @nargs: the number of arguments
6450 *
6451 * Implement the substring-before() XPath function
6452 * string substring-before(string, string)
6453 * The substring-before function returns the substring of the first
6454 * argument string that precedes the first occurrence of the second
6455 * argument string in the first argument string, or the empty string
6456 * if the first argument string does not contain the second argument
6457 * string. For example, substring-before("1999/04/01","/") returns 1999.
6458 */
6459void
6460xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6461 xmlXPathObjectPtr str;
6462 xmlXPathObjectPtr find;
6463 xmlBufferPtr target;
6464 const xmlChar *point;
6465 int offset;
6466
6467 CHECK_ARITY(2);
6468 CAST_TO_STRING;
6469 find = valuePop(ctxt);
6470 CAST_TO_STRING;
6471 str = valuePop(ctxt);
6472
6473 target = xmlBufferCreate();
6474 if (target) {
6475 point = xmlStrstr(str->stringval, find->stringval);
6476 if (point) {
6477 offset = (int)(point - str->stringval);
6478 xmlBufferAdd(target, str->stringval, offset);
6479 }
6480 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6481 xmlBufferFree(target);
6482 }
6483
6484 xmlXPathFreeObject(str);
6485 xmlXPathFreeObject(find);
6486}
6487
6488/**
6489 * xmlXPathSubstringAfterFunction:
6490 * @ctxt: the XPath Parser context
6491 * @nargs: the number of arguments
6492 *
6493 * Implement the substring-after() XPath function
6494 * string substring-after(string, string)
6495 * The substring-after function returns the substring of the first
6496 * argument string that follows the first occurrence of the second
6497 * argument string in the first argument string, or the empty stringi
6498 * if the first argument string does not contain the second argument
6499 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6500 * and substring-after("1999/04/01","19") returns 99/04/01.
6501 */
6502void
6503xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6504 xmlXPathObjectPtr str;
6505 xmlXPathObjectPtr find;
6506 xmlBufferPtr target;
6507 const xmlChar *point;
6508 int offset;
6509
6510 CHECK_ARITY(2);
6511 CAST_TO_STRING;
6512 find = valuePop(ctxt);
6513 CAST_TO_STRING;
6514 str = valuePop(ctxt);
6515
6516 target = xmlBufferCreate();
6517 if (target) {
6518 point = xmlStrstr(str->stringval, find->stringval);
6519 if (point) {
6520 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6521 xmlBufferAdd(target, &str->stringval[offset],
6522 xmlStrlen(str->stringval) - offset);
6523 }
6524 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6525 xmlBufferFree(target);
6526 }
6527
6528 xmlXPathFreeObject(str);
6529 xmlXPathFreeObject(find);
6530}
6531
6532/**
6533 * xmlXPathNormalizeFunction:
6534 * @ctxt: the XPath Parser context
6535 * @nargs: the number of arguments
6536 *
6537 * Implement the normalize-space() XPath function
6538 * string normalize-space(string?)
6539 * The normalize-space function returns the argument string with white
6540 * space normalized by stripping leading and trailing whitespace
6541 * and replacing sequences of whitespace characters by a single
6542 * space. Whitespace characters are the same allowed by the S production
6543 * in XML. If the argument is omitted, it defaults to the context
6544 * node converted to a string, in other words the value of the context node.
6545 */
6546void
6547xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6548 xmlXPathObjectPtr obj = NULL;
6549 xmlChar *source = NULL;
6550 xmlBufferPtr target;
6551 xmlChar blank;
6552
6553 if (nargs == 0) {
6554 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006555 valuePush(ctxt,
6556 xmlXPathWrapString(
6557 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006558 nargs = 1;
6559 }
6560
6561 CHECK_ARITY(1);
6562 CAST_TO_STRING;
6563 CHECK_TYPE(XPATH_STRING);
6564 obj = valuePop(ctxt);
6565 source = obj->stringval;
6566
6567 target = xmlBufferCreate();
6568 if (target && source) {
6569
6570 /* Skip leading whitespaces */
6571 while (IS_BLANK(*source))
6572 source++;
6573
6574 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6575 blank = 0;
6576 while (*source) {
6577 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006578 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006579 } else {
6580 if (blank) {
6581 xmlBufferAdd(target, &blank, 1);
6582 blank = 0;
6583 }
6584 xmlBufferAdd(target, source, 1);
6585 }
6586 source++;
6587 }
6588
6589 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6590 xmlBufferFree(target);
6591 }
6592 xmlXPathFreeObject(obj);
6593}
6594
6595/**
6596 * xmlXPathTranslateFunction:
6597 * @ctxt: the XPath Parser context
6598 * @nargs: the number of arguments
6599 *
6600 * Implement the translate() XPath function
6601 * string translate(string, string, string)
6602 * The translate function returns the first argument string with
6603 * occurrences of characters in the second argument string replaced
6604 * by the character at the corresponding position in the third argument
6605 * string. For example, translate("bar","abc","ABC") returns the string
6606 * BAr. If there is a character in the second argument string with no
6607 * character at a corresponding position in the third argument string
6608 * (because the second argument string is longer than the third argument
6609 * string), then occurrences of that character in the first argument
6610 * string are removed. For example, translate("--aaa--","abc-","ABC")
6611 * returns "AAA". If a character occurs more than once in second
6612 * argument string, then the first occurrence determines the replacement
6613 * character. If the third argument string is longer than the second
6614 * argument string, then excess characters are ignored.
6615 */
6616void
6617xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006618 xmlXPathObjectPtr str;
6619 xmlXPathObjectPtr from;
6620 xmlXPathObjectPtr to;
6621 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006622 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006623 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006624 xmlChar *point;
6625 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006626
Daniel Veillarde043ee12001-04-16 14:08:07 +00006627 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006628
Daniel Veillarde043ee12001-04-16 14:08:07 +00006629 CAST_TO_STRING;
6630 to = valuePop(ctxt);
6631 CAST_TO_STRING;
6632 from = valuePop(ctxt);
6633 CAST_TO_STRING;
6634 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006635
Daniel Veillarde043ee12001-04-16 14:08:07 +00006636 target = xmlBufferCreate();
6637 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006638 max = xmlUTF8Strlen(to->stringval);
6639 for (cptr = str->stringval; (ch=*cptr); ) {
6640 offset = xmlUTF8Strloc(from->stringval, cptr);
6641 if (offset >= 0) {
6642 if (offset < max) {
6643 point = xmlUTF8Strpos(to->stringval, offset);
6644 if (point)
6645 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6646 }
6647 } else
6648 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6649
6650 /* Step to next character in input */
6651 cptr++;
6652 if ( ch & 0x80 ) {
6653 /* if not simple ascii, verify proper format */
6654 if ( (ch & 0xc0) != 0xc0 ) {
6655 xmlGenericError(xmlGenericErrorContext,
6656 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6657 break;
6658 }
6659 /* then skip over remaining bytes for this char */
6660 while ( (ch <<= 1) & 0x80 )
6661 if ( (*cptr++ & 0xc0) != 0x80 ) {
6662 xmlGenericError(xmlGenericErrorContext,
6663 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6664 break;
6665 }
6666 if (ch & 0x80) /* must have had error encountered */
6667 break;
6668 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006669 }
Owen Taylor3473f882001-02-23 17:55:21 +00006670 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006671 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6672 xmlBufferFree(target);
6673 xmlXPathFreeObject(str);
6674 xmlXPathFreeObject(from);
6675 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006676}
6677
6678/**
6679 * xmlXPathBooleanFunction:
6680 * @ctxt: the XPath Parser context
6681 * @nargs: the number of arguments
6682 *
6683 * Implement the boolean() XPath function
6684 * boolean boolean(object)
6685 * he boolean function converts its argument to a boolean as follows:
6686 * - a number is true if and only if it is neither positive or
6687 * negative zero nor NaN
6688 * - a node-set is true if and only if it is non-empty
6689 * - a string is true if and only if its length is non-zero
6690 */
6691void
6692xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6693 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006694
6695 CHECK_ARITY(1);
6696 cur = valuePop(ctxt);
6697 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006698 cur = xmlXPathConvertBoolean(cur);
6699 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006700}
6701
6702/**
6703 * xmlXPathNotFunction:
6704 * @ctxt: the XPath Parser context
6705 * @nargs: the number of arguments
6706 *
6707 * Implement the not() XPath function
6708 * boolean not(boolean)
6709 * The not function returns true if its argument is false,
6710 * and false otherwise.
6711 */
6712void
6713xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6714 CHECK_ARITY(1);
6715 CAST_TO_BOOLEAN;
6716 CHECK_TYPE(XPATH_BOOLEAN);
6717 ctxt->value->boolval = ! ctxt->value->boolval;
6718}
6719
6720/**
6721 * xmlXPathTrueFunction:
6722 * @ctxt: the XPath Parser context
6723 * @nargs: the number of arguments
6724 *
6725 * Implement the true() XPath function
6726 * boolean true()
6727 */
6728void
6729xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6730 CHECK_ARITY(0);
6731 valuePush(ctxt, xmlXPathNewBoolean(1));
6732}
6733
6734/**
6735 * xmlXPathFalseFunction:
6736 * @ctxt: the XPath Parser context
6737 * @nargs: the number of arguments
6738 *
6739 * Implement the false() XPath function
6740 * boolean false()
6741 */
6742void
6743xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6744 CHECK_ARITY(0);
6745 valuePush(ctxt, xmlXPathNewBoolean(0));
6746}
6747
6748/**
6749 * xmlXPathLangFunction:
6750 * @ctxt: the XPath Parser context
6751 * @nargs: the number of arguments
6752 *
6753 * Implement the lang() XPath function
6754 * boolean lang(string)
6755 * The lang function returns true or false depending on whether the
6756 * language of the context node as specified by xml:lang attributes
6757 * is the same as or is a sublanguage of the language specified by
6758 * the argument string. The language of the context node is determined
6759 * by the value of the xml:lang attribute on the context node, or, if
6760 * the context node has no xml:lang attribute, by the value of the
6761 * xml:lang attribute on the nearest ancestor of the context node that
6762 * has an xml:lang attribute. If there is no such attribute, then lang
6763 * returns false. If there is such an attribute, then lang returns
6764 * true if the attribute value is equal to the argument ignoring case,
6765 * or if there is some suffix starting with - such that the attribute
6766 * value is equal to the argument ignoring that suffix of the attribute
6767 * value and ignoring case.
6768 */
6769void
6770xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6771 xmlXPathObjectPtr val;
6772 const xmlChar *theLang;
6773 const xmlChar *lang;
6774 int ret = 0;
6775 int i;
6776
6777 CHECK_ARITY(1);
6778 CAST_TO_STRING;
6779 CHECK_TYPE(XPATH_STRING);
6780 val = valuePop(ctxt);
6781 lang = val->stringval;
6782 theLang = xmlNodeGetLang(ctxt->context->node);
6783 if ((theLang != NULL) && (lang != NULL)) {
6784 for (i = 0;lang[i] != 0;i++)
6785 if (toupper(lang[i]) != toupper(theLang[i]))
6786 goto not_equal;
6787 ret = 1;
6788 }
6789not_equal:
6790 xmlXPathFreeObject(val);
6791 valuePush(ctxt, xmlXPathNewBoolean(ret));
6792}
6793
6794/**
6795 * xmlXPathNumberFunction:
6796 * @ctxt: the XPath Parser context
6797 * @nargs: the number of arguments
6798 *
6799 * Implement the number() XPath function
6800 * number number(object?)
6801 */
6802void
6803xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6804 xmlXPathObjectPtr cur;
6805 double res;
6806
6807 if (nargs == 0) {
6808 if (ctxt->context->node == NULL) {
6809 valuePush(ctxt, xmlXPathNewFloat(0.0));
6810 } else {
6811 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6812
6813 res = xmlXPathStringEvalNumber(content);
6814 valuePush(ctxt, xmlXPathNewFloat(res));
6815 xmlFree(content);
6816 }
6817 return;
6818 }
6819
6820 CHECK_ARITY(1);
6821 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006822 cur = xmlXPathConvertNumber(cur);
6823 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006824}
6825
6826/**
6827 * xmlXPathSumFunction:
6828 * @ctxt: the XPath Parser context
6829 * @nargs: the number of arguments
6830 *
6831 * Implement the sum() XPath function
6832 * number sum(node-set)
6833 * The sum function returns the sum of the values of the nodes in
6834 * the argument node-set.
6835 */
6836void
6837xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6838 xmlXPathObjectPtr cur;
6839 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006840 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00006841
6842 CHECK_ARITY(1);
6843 if ((ctxt->value == NULL) ||
6844 ((ctxt->value->type != XPATH_NODESET) &&
6845 (ctxt->value->type != XPATH_XSLT_TREE)))
6846 XP_ERROR(XPATH_INVALID_TYPE);
6847 cur = valuePop(ctxt);
6848
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006849 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006850 valuePush(ctxt, xmlXPathNewFloat(0.0));
6851 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006852 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
6853 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006854 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006855 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00006856 }
6857 xmlXPathFreeObject(cur);
6858}
6859
6860/**
6861 * xmlXPathFloorFunction:
6862 * @ctxt: the XPath Parser context
6863 * @nargs: the number of arguments
6864 *
6865 * Implement the floor() XPath function
6866 * number floor(number)
6867 * The floor function returns the largest (closest to positive infinity)
6868 * number that is not greater than the argument and that is an integer.
6869 */
6870void
6871xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006872 double f;
6873
Owen Taylor3473f882001-02-23 17:55:21 +00006874 CHECK_ARITY(1);
6875 CAST_TO_NUMBER;
6876 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006877
6878 f = (double)((int) ctxt->value->floatval);
6879 if (f != ctxt->value->floatval) {
6880 if (ctxt->value->floatval > 0)
6881 ctxt->value->floatval = f;
6882 else
6883 ctxt->value->floatval = f - 1;
6884 }
Owen Taylor3473f882001-02-23 17:55:21 +00006885}
6886
6887/**
6888 * xmlXPathCeilingFunction:
6889 * @ctxt: the XPath Parser context
6890 * @nargs: the number of arguments
6891 *
6892 * Implement the ceiling() XPath function
6893 * number ceiling(number)
6894 * The ceiling function returns the smallest (closest to negative infinity)
6895 * number that is not less than the argument and that is an integer.
6896 */
6897void
6898xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6899 double f;
6900
6901 CHECK_ARITY(1);
6902 CAST_TO_NUMBER;
6903 CHECK_TYPE(XPATH_NUMBER);
6904
6905#if 0
6906 ctxt->value->floatval = ceil(ctxt->value->floatval);
6907#else
6908 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006909 if (f != ctxt->value->floatval) {
6910 if (ctxt->value->floatval > 0)
6911 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00006912 else {
6913 if (ctxt->value->floatval < 0 && f == 0)
6914 ctxt->value->floatval = xmlXPathNZERO;
6915 else
6916 ctxt->value->floatval = f;
6917 }
6918
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006919 }
Owen Taylor3473f882001-02-23 17:55:21 +00006920#endif
6921}
6922
6923/**
6924 * xmlXPathRoundFunction:
6925 * @ctxt: the XPath Parser context
6926 * @nargs: the number of arguments
6927 *
6928 * Implement the round() XPath function
6929 * number round(number)
6930 * The round function returns the number that is closest to the
6931 * argument and that is an integer. If there are two such numbers,
6932 * then the one that is even is returned.
6933 */
6934void
6935xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6936 double f;
6937
6938 CHECK_ARITY(1);
6939 CAST_TO_NUMBER;
6940 CHECK_TYPE(XPATH_NUMBER);
6941
Daniel Veillardcda96922001-08-21 10:56:31 +00006942 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
6943 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
6944 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00006945 (ctxt->value->floatval == 0.0))
6946 return;
6947
Owen Taylor3473f882001-02-23 17:55:21 +00006948 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006949 if (ctxt->value->floatval < 0) {
6950 if (ctxt->value->floatval < f - 0.5)
6951 ctxt->value->floatval = f - 1;
6952 else
6953 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00006954 if (ctxt->value->floatval == 0)
6955 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006956 } else {
6957 if (ctxt->value->floatval < f + 0.5)
6958 ctxt->value->floatval = f;
6959 else
6960 ctxt->value->floatval = f + 1;
6961 }
Owen Taylor3473f882001-02-23 17:55:21 +00006962}
6963
6964/************************************************************************
6965 * *
6966 * The Parser *
6967 * *
6968 ************************************************************************/
6969
6970/*
6971 * a couple of forward declarations since we use a recursive call based
6972 * implementation.
6973 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006974static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006975static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006976static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006977static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00006978static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
6979 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00006980
6981/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00006982 * xmlXPathCurrentChar:
6983 * @ctxt: the XPath parser context
6984 * @cur: pointer to the beginning of the char
6985 * @len: pointer to the length of the char read
6986 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006987 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00006988 * bytes in the input buffer.
6989 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006990 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00006991 */
6992
6993static int
6994xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
6995 unsigned char c;
6996 unsigned int val;
6997 const xmlChar *cur;
6998
6999 if (ctxt == NULL)
7000 return(0);
7001 cur = ctxt->cur;
7002
7003 /*
7004 * We are supposed to handle UTF8, check it's valid
7005 * From rfc2044: encoding of the Unicode values on UTF-8:
7006 *
7007 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
7008 * 0000 0000-0000 007F 0xxxxxxx
7009 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
7010 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
7011 *
7012 * Check for the 0x110000 limit too
7013 */
7014 c = *cur;
7015 if (c & 0x80) {
7016 if ((cur[1] & 0xc0) != 0x80)
7017 goto encoding_error;
7018 if ((c & 0xe0) == 0xe0) {
7019
7020 if ((cur[2] & 0xc0) != 0x80)
7021 goto encoding_error;
7022 if ((c & 0xf0) == 0xf0) {
7023 if (((c & 0xf8) != 0xf0) ||
7024 ((cur[3] & 0xc0) != 0x80))
7025 goto encoding_error;
7026 /* 4-byte code */
7027 *len = 4;
7028 val = (cur[0] & 0x7) << 18;
7029 val |= (cur[1] & 0x3f) << 12;
7030 val |= (cur[2] & 0x3f) << 6;
7031 val |= cur[3] & 0x3f;
7032 } else {
7033 /* 3-byte code */
7034 *len = 3;
7035 val = (cur[0] & 0xf) << 12;
7036 val |= (cur[1] & 0x3f) << 6;
7037 val |= cur[2] & 0x3f;
7038 }
7039 } else {
7040 /* 2-byte code */
7041 *len = 2;
7042 val = (cur[0] & 0x1f) << 6;
7043 val |= cur[1] & 0x3f;
7044 }
7045 if (!IS_CHAR(val)) {
7046 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
7047 }
7048 return(val);
7049 } else {
7050 /* 1-byte code */
7051 *len = 1;
7052 return((int) *cur);
7053 }
7054encoding_error:
7055 /*
7056 * If we detect an UTF8 error that probably mean that the
7057 * input encoding didn't get properly advertized in the
7058 * declaration header. Report the error and switch the encoding
7059 * to ISO-Latin-1 (if you don't like this policy, just declare the
7060 * encoding !)
7061 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00007062 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00007063 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007064}
7065
7066/**
Owen Taylor3473f882001-02-23 17:55:21 +00007067 * xmlXPathParseNCName:
7068 * @ctxt: the XPath Parser context
7069 *
7070 * parse an XML namespace non qualified name.
7071 *
7072 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7073 *
7074 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7075 * CombiningChar | Extender
7076 *
7077 * Returns the namespace name or NULL
7078 */
7079
7080xmlChar *
7081xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00007082 const xmlChar *in;
7083 xmlChar *ret;
7084 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007085
Daniel Veillard2156a562001-04-28 12:24:34 +00007086 /*
7087 * Accelerator for simple ASCII names
7088 */
7089 in = ctxt->cur;
7090 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7091 ((*in >= 0x41) && (*in <= 0x5A)) ||
7092 (*in == '_')) {
7093 in++;
7094 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7095 ((*in >= 0x41) && (*in <= 0x5A)) ||
7096 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00007097 (*in == '_') || (*in == '.') ||
7098 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00007099 in++;
7100 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7101 (*in == '[') || (*in == ']') || (*in == ':') ||
7102 (*in == '@') || (*in == '*')) {
7103 count = in - ctxt->cur;
7104 if (count == 0)
7105 return(NULL);
7106 ret = xmlStrndup(ctxt->cur, count);
7107 ctxt->cur = in;
7108 return(ret);
7109 }
7110 }
7111 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00007112}
7113
Daniel Veillard2156a562001-04-28 12:24:34 +00007114
Owen Taylor3473f882001-02-23 17:55:21 +00007115/**
7116 * xmlXPathParseQName:
7117 * @ctxt: the XPath Parser context
7118 * @prefix: a xmlChar **
7119 *
7120 * parse an XML qualified name
7121 *
7122 * [NS 5] QName ::= (Prefix ':')? LocalPart
7123 *
7124 * [NS 6] Prefix ::= NCName
7125 *
7126 * [NS 7] LocalPart ::= NCName
7127 *
7128 * Returns the function returns the local part, and prefix is updated
7129 * to get the Prefix if any.
7130 */
7131
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007132static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007133xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7134 xmlChar *ret = NULL;
7135
7136 *prefix = NULL;
7137 ret = xmlXPathParseNCName(ctxt);
7138 if (CUR == ':') {
7139 *prefix = ret;
7140 NEXT;
7141 ret = xmlXPathParseNCName(ctxt);
7142 }
7143 return(ret);
7144}
7145
7146/**
7147 * xmlXPathParseName:
7148 * @ctxt: the XPath Parser context
7149 *
7150 * parse an XML name
7151 *
7152 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7153 * CombiningChar | Extender
7154 *
7155 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7156 *
7157 * Returns the namespace name or NULL
7158 */
7159
7160xmlChar *
7161xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007162 const xmlChar *in;
7163 xmlChar *ret;
7164 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007165
Daniel Veillard61d80a22001-04-27 17:13:01 +00007166 /*
7167 * Accelerator for simple ASCII names
7168 */
7169 in = ctxt->cur;
7170 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7171 ((*in >= 0x41) && (*in <= 0x5A)) ||
7172 (*in == '_') || (*in == ':')) {
7173 in++;
7174 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7175 ((*in >= 0x41) && (*in <= 0x5A)) ||
7176 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00007177 (*in == '_') || (*in == '-') ||
7178 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00007179 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007180 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007181 count = in - ctxt->cur;
7182 ret = xmlStrndup(ctxt->cur, count);
7183 ctxt->cur = in;
7184 return(ret);
7185 }
7186 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007187 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00007188}
7189
Daniel Veillard61d80a22001-04-27 17:13:01 +00007190static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00007191xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007192 xmlChar buf[XML_MAX_NAMELEN + 5];
7193 int len = 0, l;
7194 int c;
7195
7196 /*
7197 * Handler for more complex cases
7198 */
7199 c = CUR_CHAR(l);
7200 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00007201 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7202 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00007203 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00007204 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007205 return(NULL);
7206 }
7207
7208 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7209 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7210 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007211 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007212 (IS_COMBINING(c)) ||
7213 (IS_EXTENDER(c)))) {
7214 COPY_BUF(l,buf,len,c);
7215 NEXTL(l);
7216 c = CUR_CHAR(l);
7217 if (len >= XML_MAX_NAMELEN) {
7218 /*
7219 * Okay someone managed to make a huge name, so he's ready to pay
7220 * for the processing speed.
7221 */
7222 xmlChar *buffer;
7223 int max = len * 2;
7224
7225 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
7226 if (buffer == NULL) {
7227 XP_ERROR0(XPATH_MEMORY_ERROR);
7228 }
7229 memcpy(buffer, buf, len);
7230 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7231 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007232 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007233 (IS_COMBINING(c)) ||
7234 (IS_EXTENDER(c))) {
7235 if (len + 10 > max) {
7236 max *= 2;
7237 buffer = (xmlChar *) xmlRealloc(buffer,
7238 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007239 if (buffer == NULL) {
7240 XP_ERROR0(XPATH_MEMORY_ERROR);
7241 }
7242 }
7243 COPY_BUF(l,buffer,len,c);
7244 NEXTL(l);
7245 c = CUR_CHAR(l);
7246 }
7247 buffer[len] = 0;
7248 return(buffer);
7249 }
7250 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007251 if (len == 0)
7252 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007253 return(xmlStrndup(buf, len));
7254}
Daniel Veillard3cd72402002-05-13 10:33:30 +00007255
7256#define MAX_FRAC 20
7257
7258static double my_pow10[MAX_FRAC] = {
7259 1.0, 10.0, 100.0, 1000.0, 10000.0,
7260 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7261 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7262 100000000000000.0,
7263 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
7264 1000000000000000000.0, 10000000000000000000.0
7265};
7266
Owen Taylor3473f882001-02-23 17:55:21 +00007267/**
7268 * xmlXPathStringEvalNumber:
7269 * @str: A string to scan
7270 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00007271 * [30a] Float ::= Number ('e' Digits?)?
7272 *
Owen Taylor3473f882001-02-23 17:55:21 +00007273 * [30] Number ::= Digits ('.' Digits?)?
7274 * | '.' Digits
7275 * [31] Digits ::= [0-9]+
7276 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007277 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00007278 * In complement of the Number expression, this function also handles
7279 * negative values : '-' Number.
7280 *
7281 * Returns the double value.
7282 */
7283double
7284xmlXPathStringEvalNumber(const xmlChar *str) {
7285 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00007286 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007287 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007288 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007289 int exponent = 0;
7290 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007291#ifdef __GNUC__
7292 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007293 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007294#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00007295 if (cur == NULL) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00007296 while (IS_BLANK(*cur)) cur++;
7297 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7298 return(xmlXPathNAN);
7299 }
7300 if (*cur == '-') {
7301 isneg = 1;
7302 cur++;
7303 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007304
7305#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007306 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007307 * tmp/temp is a workaround against a gcc compiler bug
7308 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007309 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007310 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007311 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007312 ret = ret * 10;
7313 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00007314 ok = 1;
7315 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00007316 temp = (double) tmp;
7317 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007318 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007319#else
Daniel Veillard7b416132002-03-07 08:36:03 +00007320 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007321 while ((*cur >= '0') && (*cur <= '9')) {
7322 ret = ret * 10 + (*cur - '0');
7323 ok = 1;
7324 cur++;
7325 }
7326#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007327
Owen Taylor3473f882001-02-23 17:55:21 +00007328 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007329 int v, frac = 0;
7330 double fraction = 0;
7331
Owen Taylor3473f882001-02-23 17:55:21 +00007332 cur++;
7333 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7334 return(xmlXPathNAN);
7335 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007336 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
7337 v = (*cur - '0');
7338 fraction = fraction * 10 + v;
7339 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007340 cur++;
7341 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007342 fraction /= my_pow10[frac];
7343 ret = ret + fraction;
7344 while ((*cur >= '0') && (*cur <= '9'))
7345 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007346 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007347 if ((*cur == 'e') || (*cur == 'E')) {
7348 cur++;
7349 if (*cur == '-') {
7350 is_exponent_negative = 1;
7351 cur++;
7352 }
7353 while ((*cur >= '0') && (*cur <= '9')) {
7354 exponent = exponent * 10 + (*cur - '0');
7355 cur++;
7356 }
7357 }
Owen Taylor3473f882001-02-23 17:55:21 +00007358 while (IS_BLANK(*cur)) cur++;
7359 if (*cur != 0) return(xmlXPathNAN);
7360 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007361 if (is_exponent_negative) exponent = -exponent;
7362 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007363 return(ret);
7364}
7365
7366/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007367 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007368 * @ctxt: the XPath Parser context
7369 *
7370 * [30] Number ::= Digits ('.' Digits?)?
7371 * | '.' Digits
7372 * [31] Digits ::= [0-9]+
7373 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007374 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007375 *
7376 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007377static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007378xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7379{
Owen Taylor3473f882001-02-23 17:55:21 +00007380 double ret = 0.0;
7381 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007382 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007383 int exponent = 0;
7384 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007385#ifdef __GNUC__
7386 unsigned long tmp = 0;
7387 double temp;
7388#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007389
7390 CHECK_ERROR;
7391 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7392 XP_ERROR(XPATH_NUMBER_ERROR);
7393 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007394#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007395 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007396 * tmp/temp is a workaround against a gcc compiler bug
7397 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007398 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007399 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007400 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007401 ret = ret * 10;
7402 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007403 ok = 1;
7404 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007405 temp = (double) tmp;
7406 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007407 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007408#else
7409 ret = 0;
7410 while ((CUR >= '0') && (CUR <= '9')) {
7411 ret = ret * 10 + (CUR - '0');
7412 ok = 1;
7413 NEXT;
7414 }
7415#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007416 if (CUR == '.') {
7417 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007418 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7419 XP_ERROR(XPATH_NUMBER_ERROR);
7420 }
7421 while ((CUR >= '0') && (CUR <= '9')) {
7422 mult /= 10;
7423 ret = ret + (CUR - '0') * mult;
7424 NEXT;
7425 }
Owen Taylor3473f882001-02-23 17:55:21 +00007426 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007427 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007428 NEXT;
7429 if (CUR == '-') {
7430 is_exponent_negative = 1;
7431 NEXT;
7432 }
7433 while ((CUR >= '0') && (CUR <= '9')) {
7434 exponent = exponent * 10 + (CUR - '0');
7435 NEXT;
7436 }
7437 if (is_exponent_negative)
7438 exponent = -exponent;
7439 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007440 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007441 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007442 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007443}
7444
7445/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007446 * xmlXPathParseLiteral:
7447 * @ctxt: the XPath Parser context
7448 *
7449 * Parse a Literal
7450 *
7451 * [29] Literal ::= '"' [^"]* '"'
7452 * | "'" [^']* "'"
7453 *
7454 * Returns the value found or NULL in case of error
7455 */
7456static xmlChar *
7457xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7458 const xmlChar *q;
7459 xmlChar *ret = NULL;
7460
7461 if (CUR == '"') {
7462 NEXT;
7463 q = CUR_PTR;
7464 while ((IS_CHAR(CUR)) && (CUR != '"'))
7465 NEXT;
7466 if (!IS_CHAR(CUR)) {
7467 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7468 } else {
7469 ret = xmlStrndup(q, CUR_PTR - q);
7470 NEXT;
7471 }
7472 } else if (CUR == '\'') {
7473 NEXT;
7474 q = CUR_PTR;
7475 while ((IS_CHAR(CUR)) && (CUR != '\''))
7476 NEXT;
7477 if (!IS_CHAR(CUR)) {
7478 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7479 } else {
7480 ret = xmlStrndup(q, CUR_PTR - q);
7481 NEXT;
7482 }
7483 } else {
7484 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7485 }
7486 return(ret);
7487}
7488
7489/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007490 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007491 * @ctxt: the XPath Parser context
7492 *
7493 * Parse a Literal and push it on the stack.
7494 *
7495 * [29] Literal ::= '"' [^"]* '"'
7496 * | "'" [^']* "'"
7497 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007498 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007499 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007500static void
7501xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007502 const xmlChar *q;
7503 xmlChar *ret = NULL;
7504
7505 if (CUR == '"') {
7506 NEXT;
7507 q = CUR_PTR;
7508 while ((IS_CHAR(CUR)) && (CUR != '"'))
7509 NEXT;
7510 if (!IS_CHAR(CUR)) {
7511 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7512 } else {
7513 ret = xmlStrndup(q, CUR_PTR - q);
7514 NEXT;
7515 }
7516 } else if (CUR == '\'') {
7517 NEXT;
7518 q = CUR_PTR;
7519 while ((IS_CHAR(CUR)) && (CUR != '\''))
7520 NEXT;
7521 if (!IS_CHAR(CUR)) {
7522 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7523 } else {
7524 ret = xmlStrndup(q, CUR_PTR - q);
7525 NEXT;
7526 }
7527 } else {
7528 XP_ERROR(XPATH_START_LITERAL_ERROR);
7529 }
7530 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007531 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7532 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007533 xmlFree(ret);
7534}
7535
7536/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007537 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007538 * @ctxt: the XPath Parser context
7539 *
7540 * Parse a VariableReference, evaluate it and push it on the stack.
7541 *
7542 * The variable bindings consist of a mapping from variable names
7543 * to variable values. The value of a variable is an object, which
7544 * of any of the types that are possible for the value of an expression,
7545 * and may also be of additional types not specified here.
7546 *
7547 * Early evaluation is possible since:
7548 * The variable bindings [...] used to evaluate a subexpression are
7549 * always the same as those used to evaluate the containing expression.
7550 *
7551 * [36] VariableReference ::= '$' QName
7552 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007553static void
7554xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007555 xmlChar *name;
7556 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007557
7558 SKIP_BLANKS;
7559 if (CUR != '$') {
7560 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7561 }
7562 NEXT;
7563 name = xmlXPathParseQName(ctxt, &prefix);
7564 if (name == NULL) {
7565 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7566 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007567 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007568 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7569 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007570 SKIP_BLANKS;
7571}
7572
7573/**
7574 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +00007575 * @name: a name string
7576 *
7577 * Is the name given a NodeType one.
7578 *
7579 * [38] NodeType ::= 'comment'
7580 * | 'text'
7581 * | 'processing-instruction'
7582 * | 'node'
7583 *
7584 * Returns 1 if true 0 otherwise
7585 */
7586int
7587xmlXPathIsNodeType(const xmlChar *name) {
7588 if (name == NULL)
7589 return(0);
7590
Daniel Veillard1971ee22002-01-31 20:29:19 +00007591 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007592 return(1);
7593 if (xmlStrEqual(name, BAD_CAST "text"))
7594 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007595 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007596 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007597 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007598 return(1);
7599 return(0);
7600}
7601
7602/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007603 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007604 * @ctxt: the XPath Parser context
7605 *
7606 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7607 * [17] Argument ::= Expr
7608 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007609 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007610 * pushed on the stack
7611 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007612static void
7613xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007614 xmlChar *name;
7615 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007616 int nbargs = 0;
7617
7618 name = xmlXPathParseQName(ctxt, &prefix);
7619 if (name == NULL) {
7620 XP_ERROR(XPATH_EXPR_ERROR);
7621 }
7622 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007623#ifdef DEBUG_EXPR
7624 if (prefix == NULL)
7625 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7626 name);
7627 else
7628 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7629 prefix, name);
7630#endif
7631
Owen Taylor3473f882001-02-23 17:55:21 +00007632 if (CUR != '(') {
7633 XP_ERROR(XPATH_EXPR_ERROR);
7634 }
7635 NEXT;
7636 SKIP_BLANKS;
7637
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007638 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +00007639 if (CUR != ')') {
7640 while (CUR != 0) {
7641 int op1 = ctxt->comp->last;
7642 ctxt->comp->last = -1;
7643 xmlXPathCompileExpr(ctxt);
7644 CHECK_ERROR;
7645 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
7646 nbargs++;
7647 if (CUR == ')') break;
7648 if (CUR != ',') {
7649 XP_ERROR(XPATH_EXPR_ERROR);
7650 }
7651 NEXT;
7652 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007653 }
Owen Taylor3473f882001-02-23 17:55:21 +00007654 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007655 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7656 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007657 NEXT;
7658 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007659}
7660
7661/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007662 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007663 * @ctxt: the XPath Parser context
7664 *
7665 * [15] PrimaryExpr ::= VariableReference
7666 * | '(' Expr ')'
7667 * | Literal
7668 * | Number
7669 * | FunctionCall
7670 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007671 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007672 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007673static void
7674xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007675 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007676 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007677 else if (CUR == '(') {
7678 NEXT;
7679 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007680 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007681 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00007682 if (CUR != ')') {
7683 XP_ERROR(XPATH_EXPR_ERROR);
7684 }
7685 NEXT;
7686 SKIP_BLANKS;
Daniel Veillard01917aa2002-04-10 11:30:41 +00007687 } else if (IS_DIGIT(CUR) || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007688 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007689 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007690 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007691 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007692 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007693 }
7694 SKIP_BLANKS;
7695}
7696
7697/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007698 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007699 * @ctxt: the XPath Parser context
7700 *
7701 * [20] FilterExpr ::= PrimaryExpr
7702 * | FilterExpr Predicate
7703 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007704 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007705 * Square brackets are used to filter expressions in the same way that
7706 * they are used in location paths. It is an error if the expression to
7707 * be filtered does not evaluate to a node-set. The context node list
7708 * used for evaluating the expression in square brackets is the node-set
7709 * to be filtered listed in document order.
7710 */
7711
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007712static void
7713xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
7714 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007715 CHECK_ERROR;
7716 SKIP_BLANKS;
7717
7718 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007719 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00007720 SKIP_BLANKS;
7721 }
7722
7723
7724}
7725
7726/**
7727 * xmlXPathScanName:
7728 * @ctxt: the XPath Parser context
7729 *
7730 * Trickery: parse an XML name but without consuming the input flow
7731 * Needed to avoid insanity in the parser state.
7732 *
7733 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7734 * CombiningChar | Extender
7735 *
7736 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7737 *
7738 * [6] Names ::= Name (S Name)*
7739 *
7740 * Returns the Name parsed or NULL
7741 */
7742
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007743static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007744xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7745 xmlChar buf[XML_MAX_NAMELEN];
7746 int len = 0;
7747
7748 SKIP_BLANKS;
7749 if (!IS_LETTER(CUR) && (CUR != '_') &&
7750 (CUR != ':')) {
7751 return(NULL);
7752 }
7753
7754 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7755 (NXT(len) == '.') || (NXT(len) == '-') ||
7756 (NXT(len) == '_') || (NXT(len) == ':') ||
7757 (IS_COMBINING(NXT(len))) ||
7758 (IS_EXTENDER(NXT(len)))) {
7759 buf[len] = NXT(len);
7760 len++;
7761 if (len >= XML_MAX_NAMELEN) {
7762 xmlGenericError(xmlGenericErrorContext,
7763 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
7764 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7765 (NXT(len) == '.') || (NXT(len) == '-') ||
7766 (NXT(len) == '_') || (NXT(len) == ':') ||
7767 (IS_COMBINING(NXT(len))) ||
7768 (IS_EXTENDER(NXT(len))))
7769 len++;
7770 break;
7771 }
7772 }
7773 return(xmlStrndup(buf, len));
7774}
7775
7776/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007777 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007778 * @ctxt: the XPath Parser context
7779 *
7780 * [19] PathExpr ::= LocationPath
7781 * | FilterExpr
7782 * | FilterExpr '/' RelativeLocationPath
7783 * | FilterExpr '//' RelativeLocationPath
7784 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007785 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007786 * The / operator and // operators combine an arbitrary expression
7787 * and a relative location path. It is an error if the expression
7788 * does not evaluate to a node-set.
7789 * The / operator does composition in the same way as when / is
7790 * used in a location path. As in location paths, // is short for
7791 * /descendant-or-self::node()/.
7792 */
7793
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007794static void
7795xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007796 int lc = 1; /* Should we branch to LocationPath ? */
7797 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7798
7799 SKIP_BLANKS;
7800 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
Daniel Veillard01917aa2002-04-10 11:30:41 +00007801 (CUR == '\'') || (CUR == '"') || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00007802 lc = 0;
7803 } else if (CUR == '*') {
7804 /* relative or absolute location path */
7805 lc = 1;
7806 } else if (CUR == '/') {
7807 /* relative or absolute location path */
7808 lc = 1;
7809 } else if (CUR == '@') {
7810 /* relative abbreviated attribute location path */
7811 lc = 1;
7812 } else if (CUR == '.') {
7813 /* relative abbreviated attribute location path */
7814 lc = 1;
7815 } else {
7816 /*
7817 * Problem is finding if we have a name here whether it's:
7818 * - a nodetype
7819 * - a function call in which case it's followed by '('
7820 * - an axis in which case it's followed by ':'
7821 * - a element name
7822 * We do an a priori analysis here rather than having to
7823 * maintain parsed token content through the recursive function
7824 * calls. This looks uglier but makes the code quite easier to
7825 * read/write/debug.
7826 */
7827 SKIP_BLANKS;
7828 name = xmlXPathScanName(ctxt);
7829 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7830#ifdef DEBUG_STEP
7831 xmlGenericError(xmlGenericErrorContext,
7832 "PathExpr: Axis\n");
7833#endif
7834 lc = 1;
7835 xmlFree(name);
7836 } else if (name != NULL) {
7837 int len =xmlStrlen(name);
7838 int blank = 0;
7839
7840
7841 while (NXT(len) != 0) {
7842 if (NXT(len) == '/') {
7843 /* element name */
7844#ifdef DEBUG_STEP
7845 xmlGenericError(xmlGenericErrorContext,
7846 "PathExpr: AbbrRelLocation\n");
7847#endif
7848 lc = 1;
7849 break;
7850 } else if (IS_BLANK(NXT(len))) {
7851 /* skip to next */
7852 blank = 1;
7853 } else if (NXT(len) == ':') {
7854#ifdef DEBUG_STEP
7855 xmlGenericError(xmlGenericErrorContext,
7856 "PathExpr: AbbrRelLocation\n");
7857#endif
7858 lc = 1;
7859 break;
7860 } else if ((NXT(len) == '(')) {
7861 /* Note Type or Function */
7862 if (xmlXPathIsNodeType(name)) {
7863#ifdef DEBUG_STEP
7864 xmlGenericError(xmlGenericErrorContext,
7865 "PathExpr: Type search\n");
7866#endif
7867 lc = 1;
7868 } else {
7869#ifdef DEBUG_STEP
7870 xmlGenericError(xmlGenericErrorContext,
7871 "PathExpr: function call\n");
7872#endif
7873 lc = 0;
7874 }
7875 break;
7876 } else if ((NXT(len) == '[')) {
7877 /* element name */
7878#ifdef DEBUG_STEP
7879 xmlGenericError(xmlGenericErrorContext,
7880 "PathExpr: AbbrRelLocation\n");
7881#endif
7882 lc = 1;
7883 break;
7884 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
7885 (NXT(len) == '=')) {
7886 lc = 1;
7887 break;
7888 } else {
7889 lc = 1;
7890 break;
7891 }
7892 len++;
7893 }
7894 if (NXT(len) == 0) {
7895#ifdef DEBUG_STEP
7896 xmlGenericError(xmlGenericErrorContext,
7897 "PathExpr: AbbrRelLocation\n");
7898#endif
7899 /* element name */
7900 lc = 1;
7901 }
7902 xmlFree(name);
7903 } else {
7904 /* make sure all cases are covered explicitely */
7905 XP_ERROR(XPATH_EXPR_ERROR);
7906 }
7907 }
7908
7909 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007910 if (CUR == '/') {
7911 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
7912 } else {
7913 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007914 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007915 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007916 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007917 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007918 CHECK_ERROR;
7919 if ((CUR == '/') && (NXT(1) == '/')) {
7920 SKIP(2);
7921 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007922
7923 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7924 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
7925 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
7926
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007927 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007928 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007929 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007930 }
7931 }
7932 SKIP_BLANKS;
7933}
7934
7935/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007936 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007937 * @ctxt: the XPath Parser context
7938 *
7939 * [18] UnionExpr ::= PathExpr
7940 * | UnionExpr '|' PathExpr
7941 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007942 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007943 */
7944
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007945static void
7946xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
7947 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007948 CHECK_ERROR;
7949 SKIP_BLANKS;
7950 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007951 int op1 = ctxt->comp->last;
7952 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007953
7954 NEXT;
7955 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007956 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007957
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007958 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
7959
Owen Taylor3473f882001-02-23 17:55:21 +00007960 SKIP_BLANKS;
7961 }
Owen Taylor3473f882001-02-23 17:55:21 +00007962}
7963
7964/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007965 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007966 * @ctxt: the XPath Parser context
7967 *
7968 * [27] UnaryExpr ::= UnionExpr
7969 * | '-' UnaryExpr
7970 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007971 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007972 */
7973
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007974static void
7975xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007976 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007977 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007978
7979 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00007980 while (CUR == '-') {
7981 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007982 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007983 NEXT;
7984 SKIP_BLANKS;
7985 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007986
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007987 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007988 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007989 if (found) {
7990 if (minus)
7991 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
7992 else
7993 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007994 }
7995}
7996
7997/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007998 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007999 * @ctxt: the XPath Parser context
8000 *
8001 * [26] MultiplicativeExpr ::= UnaryExpr
8002 * | MultiplicativeExpr MultiplyOperator UnaryExpr
8003 * | MultiplicativeExpr 'div' UnaryExpr
8004 * | MultiplicativeExpr 'mod' UnaryExpr
8005 * [34] MultiplyOperator ::= '*'
8006 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008007 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008008 */
8009
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008010static void
8011xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8012 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008013 CHECK_ERROR;
8014 SKIP_BLANKS;
8015 while ((CUR == '*') ||
8016 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8017 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8018 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008019 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008020
8021 if (CUR == '*') {
8022 op = 0;
8023 NEXT;
8024 } else if (CUR == 'd') {
8025 op = 1;
8026 SKIP(3);
8027 } else if (CUR == 'm') {
8028 op = 2;
8029 SKIP(3);
8030 }
8031 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008032 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008033 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008034 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008035 SKIP_BLANKS;
8036 }
8037}
8038
8039/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008040 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008041 * @ctxt: the XPath Parser context
8042 *
8043 * [25] AdditiveExpr ::= MultiplicativeExpr
8044 * | AdditiveExpr '+' MultiplicativeExpr
8045 * | AdditiveExpr '-' MultiplicativeExpr
8046 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008047 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008048 */
8049
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008050static void
8051xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008052
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008053 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008054 CHECK_ERROR;
8055 SKIP_BLANKS;
8056 while ((CUR == '+') || (CUR == '-')) {
8057 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008058 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008059
8060 if (CUR == '+') plus = 1;
8061 else plus = 0;
8062 NEXT;
8063 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008064 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008065 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008066 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008067 SKIP_BLANKS;
8068 }
8069}
8070
8071/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008072 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008073 * @ctxt: the XPath Parser context
8074 *
8075 * [24] RelationalExpr ::= AdditiveExpr
8076 * | RelationalExpr '<' AdditiveExpr
8077 * | RelationalExpr '>' AdditiveExpr
8078 * | RelationalExpr '<=' AdditiveExpr
8079 * | RelationalExpr '>=' AdditiveExpr
8080 *
8081 * A <= B > C is allowed ? Answer from James, yes with
8082 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8083 * which is basically what got implemented.
8084 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008085 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00008086 * on the stack
8087 */
8088
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008089static void
8090xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8091 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008092 CHECK_ERROR;
8093 SKIP_BLANKS;
8094 while ((CUR == '<') ||
8095 (CUR == '>') ||
8096 ((CUR == '<') && (NXT(1) == '=')) ||
8097 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008098 int inf, strict;
8099 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008100
8101 if (CUR == '<') inf = 1;
8102 else inf = 0;
8103 if (NXT(1) == '=') strict = 0;
8104 else strict = 1;
8105 NEXT;
8106 if (!strict) NEXT;
8107 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008108 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008109 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008110 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00008111 SKIP_BLANKS;
8112 }
8113}
8114
8115/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008116 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008117 * @ctxt: the XPath Parser context
8118 *
8119 * [23] EqualityExpr ::= RelationalExpr
8120 * | EqualityExpr '=' RelationalExpr
8121 * | EqualityExpr '!=' RelationalExpr
8122 *
8123 * A != B != C is allowed ? Answer from James, yes with
8124 * (RelationalExpr = RelationalExpr) = RelationalExpr
8125 * (RelationalExpr != RelationalExpr) != RelationalExpr
8126 * which is basically what got implemented.
8127 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008128 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008129 *
8130 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008131static void
8132xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8133 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008134 CHECK_ERROR;
8135 SKIP_BLANKS;
8136 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008137 int eq;
8138 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008139
8140 if (CUR == '=') eq = 1;
8141 else eq = 0;
8142 NEXT;
8143 if (!eq) NEXT;
8144 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008145 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008146 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008147 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008148 SKIP_BLANKS;
8149 }
8150}
8151
8152/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008153 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008154 * @ctxt: the XPath Parser context
8155 *
8156 * [22] AndExpr ::= EqualityExpr
8157 * | AndExpr 'and' EqualityExpr
8158 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008159 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008160 *
8161 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008162static void
8163xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8164 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008165 CHECK_ERROR;
8166 SKIP_BLANKS;
8167 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008168 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008169 SKIP(3);
8170 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008171 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008172 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008173 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008174 SKIP_BLANKS;
8175 }
8176}
8177
8178/**
Daniel Veillard591b4be2003-02-09 23:33:36 +00008179 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008180 * @ctxt: the XPath Parser context
8181 *
8182 * [14] Expr ::= OrExpr
8183 * [21] OrExpr ::= AndExpr
8184 * | OrExpr 'or' AndExpr
8185 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008186 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00008187 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008188static void
8189xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8190 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008191 CHECK_ERROR;
8192 SKIP_BLANKS;
8193 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008194 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008195 SKIP(2);
8196 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008197 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008198 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008199 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8200 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00008201 SKIP_BLANKS;
8202 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008203 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8204 /* more ops could be optimized too */
8205 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8206 }
Owen Taylor3473f882001-02-23 17:55:21 +00008207}
8208
8209/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008210 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00008211 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008212 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00008213 *
8214 * [8] Predicate ::= '[' PredicateExpr ']'
8215 * [9] PredicateExpr ::= Expr
8216 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008217 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008218 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008219static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008220xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008221 int op1 = ctxt->comp->last;
8222
8223 SKIP_BLANKS;
8224 if (CUR != '[') {
8225 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8226 }
8227 NEXT;
8228 SKIP_BLANKS;
8229
8230 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008231 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008232 CHECK_ERROR;
8233
8234 if (CUR != ']') {
8235 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8236 }
8237
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008238 if (filter)
8239 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8240 else
8241 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008242
8243 NEXT;
8244 SKIP_BLANKS;
8245}
8246
8247/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008248 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00008249 * @ctxt: the XPath Parser context
8250 * @test: pointer to a xmlXPathTestVal
8251 * @type: pointer to a xmlXPathTypeVal
8252 * @prefix: placeholder for a possible name prefix
8253 *
8254 * [7] NodeTest ::= NameTest
8255 * | NodeType '(' ')'
8256 * | 'processing-instruction' '(' Literal ')'
8257 *
8258 * [37] NameTest ::= '*'
8259 * | NCName ':' '*'
8260 * | QName
8261 * [38] NodeType ::= 'comment'
8262 * | 'text'
8263 * | 'processing-instruction'
8264 * | 'node'
8265 *
8266 * Returns the name found and update @test, @type and @prefix appropriately
8267 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008268static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008269xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8270 xmlXPathTypeVal *type, const xmlChar **prefix,
8271 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008272 int blanks;
8273
8274 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8275 STRANGE;
8276 return(NULL);
8277 }
8278 *type = 0;
8279 *test = 0;
8280 *prefix = NULL;
8281 SKIP_BLANKS;
8282
8283 if ((name == NULL) && (CUR == '*')) {
8284 /*
8285 * All elements
8286 */
8287 NEXT;
8288 *test = NODE_TEST_ALL;
8289 return(NULL);
8290 }
8291
8292 if (name == NULL)
8293 name = xmlXPathParseNCName(ctxt);
8294 if (name == NULL) {
8295 XP_ERROR0(XPATH_EXPR_ERROR);
8296 }
8297
8298 blanks = IS_BLANK(CUR);
8299 SKIP_BLANKS;
8300 if (CUR == '(') {
8301 NEXT;
8302 /*
8303 * NodeType or PI search
8304 */
8305 if (xmlStrEqual(name, BAD_CAST "comment"))
8306 *type = NODE_TYPE_COMMENT;
8307 else if (xmlStrEqual(name, BAD_CAST "node"))
8308 *type = NODE_TYPE_NODE;
8309 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8310 *type = NODE_TYPE_PI;
8311 else if (xmlStrEqual(name, BAD_CAST "text"))
8312 *type = NODE_TYPE_TEXT;
8313 else {
8314 if (name != NULL)
8315 xmlFree(name);
8316 XP_ERROR0(XPATH_EXPR_ERROR);
8317 }
8318
8319 *test = NODE_TEST_TYPE;
8320
8321 SKIP_BLANKS;
8322 if (*type == NODE_TYPE_PI) {
8323 /*
8324 * Specific case: search a PI by name.
8325 */
Owen Taylor3473f882001-02-23 17:55:21 +00008326 if (name != NULL)
8327 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008328 name = NULL;
8329 if (CUR != ')') {
8330 name = xmlXPathParseLiteral(ctxt);
8331 CHECK_ERROR 0;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00008332 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00008333 SKIP_BLANKS;
8334 }
Owen Taylor3473f882001-02-23 17:55:21 +00008335 }
8336 if (CUR != ')') {
8337 if (name != NULL)
8338 xmlFree(name);
8339 XP_ERROR0(XPATH_UNCLOSED_ERROR);
8340 }
8341 NEXT;
8342 return(name);
8343 }
8344 *test = NODE_TEST_NAME;
8345 if ((!blanks) && (CUR == ':')) {
8346 NEXT;
8347
8348 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008349 * Since currently the parser context don't have a
8350 * namespace list associated:
8351 * The namespace name for this prefix can be computed
8352 * only at evaluation time. The compilation is done
8353 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008354 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008355#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008356 *prefix = xmlXPathNsLookup(ctxt->context, name);
8357 if (name != NULL)
8358 xmlFree(name);
8359 if (*prefix == NULL) {
8360 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8361 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008362#else
8363 *prefix = name;
8364#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008365
8366 if (CUR == '*') {
8367 /*
8368 * All elements
8369 */
8370 NEXT;
8371 *test = NODE_TEST_ALL;
8372 return(NULL);
8373 }
8374
8375 name = xmlXPathParseNCName(ctxt);
8376 if (name == NULL) {
8377 XP_ERROR0(XPATH_EXPR_ERROR);
8378 }
8379 }
8380 return(name);
8381}
8382
8383/**
8384 * xmlXPathIsAxisName:
8385 * @name: a preparsed name token
8386 *
8387 * [6] AxisName ::= 'ancestor'
8388 * | 'ancestor-or-self'
8389 * | 'attribute'
8390 * | 'child'
8391 * | 'descendant'
8392 * | 'descendant-or-self'
8393 * | 'following'
8394 * | 'following-sibling'
8395 * | 'namespace'
8396 * | 'parent'
8397 * | 'preceding'
8398 * | 'preceding-sibling'
8399 * | 'self'
8400 *
8401 * Returns the axis or 0
8402 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008403static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008404xmlXPathIsAxisName(const xmlChar *name) {
8405 xmlXPathAxisVal ret = 0;
8406 switch (name[0]) {
8407 case 'a':
8408 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8409 ret = AXIS_ANCESTOR;
8410 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8411 ret = AXIS_ANCESTOR_OR_SELF;
8412 if (xmlStrEqual(name, BAD_CAST "attribute"))
8413 ret = AXIS_ATTRIBUTE;
8414 break;
8415 case 'c':
8416 if (xmlStrEqual(name, BAD_CAST "child"))
8417 ret = AXIS_CHILD;
8418 break;
8419 case 'd':
8420 if (xmlStrEqual(name, BAD_CAST "descendant"))
8421 ret = AXIS_DESCENDANT;
8422 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8423 ret = AXIS_DESCENDANT_OR_SELF;
8424 break;
8425 case 'f':
8426 if (xmlStrEqual(name, BAD_CAST "following"))
8427 ret = AXIS_FOLLOWING;
8428 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8429 ret = AXIS_FOLLOWING_SIBLING;
8430 break;
8431 case 'n':
8432 if (xmlStrEqual(name, BAD_CAST "namespace"))
8433 ret = AXIS_NAMESPACE;
8434 break;
8435 case 'p':
8436 if (xmlStrEqual(name, BAD_CAST "parent"))
8437 ret = AXIS_PARENT;
8438 if (xmlStrEqual(name, BAD_CAST "preceding"))
8439 ret = AXIS_PRECEDING;
8440 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8441 ret = AXIS_PRECEDING_SIBLING;
8442 break;
8443 case 's':
8444 if (xmlStrEqual(name, BAD_CAST "self"))
8445 ret = AXIS_SELF;
8446 break;
8447 }
8448 return(ret);
8449}
8450
8451/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008452 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008453 * @ctxt: the XPath Parser context
8454 *
8455 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8456 * | AbbreviatedStep
8457 *
8458 * [12] AbbreviatedStep ::= '.' | '..'
8459 *
8460 * [5] AxisSpecifier ::= AxisName '::'
8461 * | AbbreviatedAxisSpecifier
8462 *
8463 * [13] AbbreviatedAxisSpecifier ::= '@'?
8464 *
8465 * Modified for XPtr range support as:
8466 *
8467 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8468 * | AbbreviatedStep
8469 * | 'range-to' '(' Expr ')' Predicate*
8470 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008471 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008472 * A location step of . is short for self::node(). This is
8473 * particularly useful in conjunction with //. For example, the
8474 * location path .//para is short for
8475 * self::node()/descendant-or-self::node()/child::para
8476 * and so will select all para descendant elements of the context
8477 * node.
8478 * Similarly, a location step of .. is short for parent::node().
8479 * For example, ../title is short for parent::node()/child::title
8480 * and so will select the title children of the parent of the context
8481 * node.
8482 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008483static void
8484xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008485#ifdef LIBXML_XPTR_ENABLED
8486 int rangeto = 0;
8487 int op2 = -1;
8488#endif
8489
Owen Taylor3473f882001-02-23 17:55:21 +00008490 SKIP_BLANKS;
8491 if ((CUR == '.') && (NXT(1) == '.')) {
8492 SKIP(2);
8493 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008494 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8495 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008496 } else if (CUR == '.') {
8497 NEXT;
8498 SKIP_BLANKS;
8499 } else {
8500 xmlChar *name = NULL;
8501 const xmlChar *prefix = NULL;
8502 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008503 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008504 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008505 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008506
8507 /*
8508 * The modification needed for XPointer change to the production
8509 */
8510#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008511 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008512 name = xmlXPathParseNCName(ctxt);
8513 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008514 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008515 xmlFree(name);
8516 SKIP_BLANKS;
8517 if (CUR != '(') {
8518 XP_ERROR(XPATH_EXPR_ERROR);
8519 }
8520 NEXT;
8521 SKIP_BLANKS;
8522
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008523 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008524 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008525 CHECK_ERROR;
8526
8527 SKIP_BLANKS;
8528 if (CUR != ')') {
8529 XP_ERROR(XPATH_EXPR_ERROR);
8530 }
8531 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008532 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008533 goto eval_predicates;
8534 }
8535 }
8536#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008537 if (CUR == '*') {
8538 axis = AXIS_CHILD;
8539 } else {
8540 if (name == NULL)
8541 name = xmlXPathParseNCName(ctxt);
8542 if (name != NULL) {
8543 axis = xmlXPathIsAxisName(name);
8544 if (axis != 0) {
8545 SKIP_BLANKS;
8546 if ((CUR == ':') && (NXT(1) == ':')) {
8547 SKIP(2);
8548 xmlFree(name);
8549 name = NULL;
8550 } else {
8551 /* an element name can conflict with an axis one :-\ */
8552 axis = AXIS_CHILD;
8553 }
Owen Taylor3473f882001-02-23 17:55:21 +00008554 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008555 axis = AXIS_CHILD;
8556 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008557 } else if (CUR == '@') {
8558 NEXT;
8559 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008560 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008561 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008562 }
Owen Taylor3473f882001-02-23 17:55:21 +00008563 }
8564
8565 CHECK_ERROR;
8566
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008567 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008568 if (test == 0)
8569 return;
8570
8571#ifdef DEBUG_STEP
8572 xmlGenericError(xmlGenericErrorContext,
8573 "Basis : computing new set\n");
8574#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008575
Owen Taylor3473f882001-02-23 17:55:21 +00008576#ifdef DEBUG_STEP
8577 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008578 if (ctxt->value == NULL)
8579 xmlGenericError(xmlGenericErrorContext, "no value\n");
8580 else if (ctxt->value->nodesetval == NULL)
8581 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8582 else
8583 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008584#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008585
8586eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008587 op1 = ctxt->comp->last;
8588 ctxt->comp->last = -1;
8589
Owen Taylor3473f882001-02-23 17:55:21 +00008590 SKIP_BLANKS;
8591 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008592 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008593 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008594
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008595#ifdef LIBXML_XPTR_ENABLED
8596 if (rangeto) {
8597 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8598 } else
8599#endif
8600 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8601 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008602
Owen Taylor3473f882001-02-23 17:55:21 +00008603 }
8604#ifdef DEBUG_STEP
8605 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008606 if (ctxt->value == NULL)
8607 xmlGenericError(xmlGenericErrorContext, "no value\n");
8608 else if (ctxt->value->nodesetval == NULL)
8609 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8610 else
8611 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8612 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008613#endif
8614}
8615
8616/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008617 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008618 * @ctxt: the XPath Parser context
8619 *
8620 * [3] RelativeLocationPath ::= Step
8621 * | RelativeLocationPath '/' Step
8622 * | AbbreviatedRelativeLocationPath
8623 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8624 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008625 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008626 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008627static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008628xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008629(xmlXPathParserContextPtr ctxt) {
8630 SKIP_BLANKS;
8631 if ((CUR == '/') && (NXT(1) == '/')) {
8632 SKIP(2);
8633 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008634 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8635 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008636 } else if (CUR == '/') {
8637 NEXT;
8638 SKIP_BLANKS;
8639 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008640 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008641 SKIP_BLANKS;
8642 while (CUR == '/') {
8643 if ((CUR == '/') && (NXT(1) == '/')) {
8644 SKIP(2);
8645 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008646 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008647 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008648 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008649 } else if (CUR == '/') {
8650 NEXT;
8651 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008652 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008653 }
8654 SKIP_BLANKS;
8655 }
8656}
8657
8658/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008659 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008660 * @ctxt: the XPath Parser context
8661 *
8662 * [1] LocationPath ::= RelativeLocationPath
8663 * | AbsoluteLocationPath
8664 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8665 * | AbbreviatedAbsoluteLocationPath
8666 * [10] AbbreviatedAbsoluteLocationPath ::=
8667 * '//' RelativeLocationPath
8668 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008669 * Compile a location path
8670 *
Owen Taylor3473f882001-02-23 17:55:21 +00008671 * // is short for /descendant-or-self::node()/. For example,
8672 * //para is short for /descendant-or-self::node()/child::para and
8673 * so will select any para element in the document (even a para element
8674 * that is a document element will be selected by //para since the
8675 * document element node is a child of the root node); div//para is
8676 * short for div/descendant-or-self::node()/child::para and so will
8677 * select all para descendants of div children.
8678 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008679static void
8680xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008681 SKIP_BLANKS;
8682 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008683 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008684 } else {
8685 while (CUR == '/') {
8686 if ((CUR == '/') && (NXT(1) == '/')) {
8687 SKIP(2);
8688 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008689 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8690 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008691 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008692 } else if (CUR == '/') {
8693 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008694 SKIP_BLANKS;
8695 if ((CUR != 0 ) &&
8696 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
8697 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008698 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008699 }
8700 }
8701 }
8702}
8703
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008704/************************************************************************
8705 * *
8706 * XPath precompiled expression evaluation *
8707 * *
8708 ************************************************************************/
8709
Daniel Veillardf06307e2001-07-03 10:35:50 +00008710static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008711xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8712
8713/**
8714 * xmlXPathNodeCollectAndTest:
8715 * @ctxt: the XPath Parser context
8716 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008717 * @first: pointer to the first element in document order
8718 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008719 *
8720 * This is the function implementing a step: based on the current list
8721 * of nodes, it builds up a new list, looking at all nodes under that
8722 * axis and selecting them it also do the predicate filtering
8723 *
8724 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00008725 *
8726 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008727 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008728static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008729xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008730 xmlXPathStepOpPtr op,
8731 xmlNodePtr * first, xmlNodePtr * last)
8732{
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008733 xmlXPathAxisVal axis = op->value;
8734 xmlXPathTestVal test = op->value2;
8735 xmlXPathTypeVal type = op->value3;
8736 const xmlChar *prefix = op->value4;
8737 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008738 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008739
8740#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008741 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008742#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008743 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008744 xmlNodeSetPtr ret, list;
8745 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008746 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00008747 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008748 xmlNodePtr cur = NULL;
8749 xmlXPathObjectPtr obj;
8750 xmlNodeSetPtr nodelist;
8751 xmlNodePtr tmp;
8752
Daniel Veillardf06307e2001-07-03 10:35:50 +00008753 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008754 obj = valuePop(ctxt);
8755 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00008756 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008757 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008758 URI = xmlXPathNsLookup(ctxt->context, prefix);
8759 if (URI == NULL)
8760 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008761 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008762#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008763 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008764#endif
8765 switch (axis) {
8766 case AXIS_ANCESTOR:
8767#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008768 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008769#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008770 first = NULL;
8771 next = xmlXPathNextAncestor;
8772 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008773 case AXIS_ANCESTOR_OR_SELF:
8774#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008775 xmlGenericError(xmlGenericErrorContext,
8776 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008777#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008778 first = NULL;
8779 next = xmlXPathNextAncestorOrSelf;
8780 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008781 case AXIS_ATTRIBUTE:
8782#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008783 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008784#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008785 first = NULL;
8786 last = NULL;
8787 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00008788 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008789 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008790 case AXIS_CHILD:
8791#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008792 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008793#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008794 last = NULL;
8795 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00008796 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008797 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008798 case AXIS_DESCENDANT:
8799#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008800 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008801#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008802 last = NULL;
8803 next = xmlXPathNextDescendant;
8804 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008805 case AXIS_DESCENDANT_OR_SELF:
8806#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008807 xmlGenericError(xmlGenericErrorContext,
8808 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008809#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008810 last = NULL;
8811 next = xmlXPathNextDescendantOrSelf;
8812 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008813 case AXIS_FOLLOWING:
8814#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008815 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008816#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008817 last = NULL;
8818 next = xmlXPathNextFollowing;
8819 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008820 case AXIS_FOLLOWING_SIBLING:
8821#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008822 xmlGenericError(xmlGenericErrorContext,
8823 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008824#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008825 last = NULL;
8826 next = xmlXPathNextFollowingSibling;
8827 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008828 case AXIS_NAMESPACE:
8829#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008830 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008831#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008832 first = NULL;
8833 last = NULL;
8834 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00008835 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008836 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008837 case AXIS_PARENT:
8838#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008839 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008840#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008841 first = NULL;
8842 next = xmlXPathNextParent;
8843 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008844 case AXIS_PRECEDING:
8845#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008846 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008847#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008848 first = NULL;
8849 next = xmlXPathNextPrecedingInternal;
8850 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008851 case AXIS_PRECEDING_SIBLING:
8852#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008853 xmlGenericError(xmlGenericErrorContext,
8854 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008855#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008856 first = NULL;
8857 next = xmlXPathNextPrecedingSibling;
8858 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008859 case AXIS_SELF:
8860#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008861 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008862#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008863 first = NULL;
8864 last = NULL;
8865 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00008866 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008867 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008868 }
8869 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008870 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008871
8872 nodelist = obj->nodesetval;
8873 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008874 xmlXPathFreeObject(obj);
8875 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8876 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008877 }
8878 addNode = xmlXPathNodeSetAddUnique;
8879 ret = NULL;
8880#ifdef DEBUG_STEP
8881 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008882 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008883 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008884 case NODE_TEST_NONE:
8885 xmlGenericError(xmlGenericErrorContext,
8886 " searching for none !!!\n");
8887 break;
8888 case NODE_TEST_TYPE:
8889 xmlGenericError(xmlGenericErrorContext,
8890 " searching for type %d\n", type);
8891 break;
8892 case NODE_TEST_PI:
8893 xmlGenericError(xmlGenericErrorContext,
8894 " searching for PI !!!\n");
8895 break;
8896 case NODE_TEST_ALL:
8897 xmlGenericError(xmlGenericErrorContext,
8898 " searching for *\n");
8899 break;
8900 case NODE_TEST_NS:
8901 xmlGenericError(xmlGenericErrorContext,
8902 " searching for namespace %s\n",
8903 prefix);
8904 break;
8905 case NODE_TEST_NAME:
8906 xmlGenericError(xmlGenericErrorContext,
8907 " searching for name %s\n", name);
8908 if (prefix != NULL)
8909 xmlGenericError(xmlGenericErrorContext,
8910 " with namespace %s\n", prefix);
8911 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008912 }
8913 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8914#endif
8915 /*
8916 * 2.3 Node Tests
8917 * - For the attribute axis, the principal node type is attribute.
8918 * - For the namespace axis, the principal node type is namespace.
8919 * - For other axes, the principal node type is element.
8920 *
8921 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008922 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008923 * select all element children of the context node
8924 */
8925 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008926 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008927 ctxt->context->node = nodelist->nodeTab[i];
8928
Daniel Veillardf06307e2001-07-03 10:35:50 +00008929 cur = NULL;
8930 list = xmlXPathNodeSetCreate(NULL);
8931 do {
8932 cur = next(ctxt, cur);
8933 if (cur == NULL)
8934 break;
8935 if ((first != NULL) && (*first == cur))
8936 break;
8937 if (((t % 256) == 0) &&
8938 (first != NULL) && (*first != NULL) &&
8939 (xmlXPathCmpNodes(*first, cur) >= 0))
8940 break;
8941 if ((last != NULL) && (*last == cur))
8942 break;
8943 if (((t % 256) == 0) &&
8944 (last != NULL) && (*last != NULL) &&
8945 (xmlXPathCmpNodes(cur, *last) >= 0))
8946 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008947 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008948#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008949 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
8950#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008951 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008952 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008953 ctxt->context->node = tmp;
8954 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008955 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008956 if ((cur->type == type) ||
8957 ((type == NODE_TYPE_NODE) &&
8958 ((cur->type == XML_DOCUMENT_NODE) ||
8959 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8960 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00008961 (cur->type == XML_NAMESPACE_DECL) ||
8962 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00008963 (cur->type == XML_PI_NODE) ||
8964 (cur->type == XML_COMMENT_NODE) ||
8965 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00008966 (cur->type == XML_TEXT_NODE))) ||
8967 ((type == NODE_TYPE_TEXT) &&
8968 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008969#ifdef DEBUG_STEP
8970 n++;
8971#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008972 addNode(list, cur);
8973 }
8974 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008975 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008976 if (cur->type == XML_PI_NODE) {
8977 if ((name != NULL) &&
8978 (!xmlStrEqual(name, cur->name)))
8979 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008980#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008981 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008982#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008983 addNode(list, cur);
8984 }
8985 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008986 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008987 if (axis == AXIS_ATTRIBUTE) {
8988 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008989#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008990 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008991#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008992 addNode(list, cur);
8993 }
8994 } else if (axis == AXIS_NAMESPACE) {
8995 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008996#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008997 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008998#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008999 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9000 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009001 }
9002 } else {
9003 if (cur->type == XML_ELEMENT_NODE) {
9004 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009005#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009006 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009007#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009008 addNode(list, cur);
9009 } else if ((cur->ns != NULL) &&
9010 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009011#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009012 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009013#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009014 addNode(list, cur);
9015 }
9016 }
9017 }
9018 break;
9019 case NODE_TEST_NS:{
9020 TODO;
9021 break;
9022 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009023 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009024 switch (cur->type) {
9025 case XML_ELEMENT_NODE:
9026 if (xmlStrEqual(name, cur->name)) {
9027 if (prefix == NULL) {
9028 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009029#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009030 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009031#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009032 addNode(list, cur);
9033 }
9034 } else {
9035 if ((cur->ns != NULL) &&
9036 (xmlStrEqual(URI,
9037 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009038#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009039 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009040#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009041 addNode(list, cur);
9042 }
9043 }
9044 }
9045 break;
9046 case XML_ATTRIBUTE_NODE:{
9047 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009048
Daniel Veillardf06307e2001-07-03 10:35:50 +00009049 if (xmlStrEqual(name, attr->name)) {
9050 if (prefix == NULL) {
9051 if ((attr->ns == NULL) ||
9052 (attr->ns->prefix == NULL)) {
9053#ifdef DEBUG_STEP
9054 n++;
9055#endif
9056 addNode(list,
9057 (xmlNodePtr) attr);
9058 }
9059 } else {
9060 if ((attr->ns != NULL) &&
9061 (xmlStrEqual(URI,
9062 attr->ns->
9063 href))) {
9064#ifdef DEBUG_STEP
9065 n++;
9066#endif
9067 addNode(list,
9068 (xmlNodePtr) attr);
9069 }
9070 }
9071 }
9072 break;
9073 }
9074 case XML_NAMESPACE_DECL:
9075 if (cur->type == XML_NAMESPACE_DECL) {
9076 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009077
Daniel Veillardf06307e2001-07-03 10:35:50 +00009078 if ((ns->prefix != NULL) && (name != NULL)
9079 && (xmlStrEqual(ns->prefix, name))) {
9080#ifdef DEBUG_STEP
9081 n++;
9082#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009083 xmlXPathNodeSetAddNs(list,
9084 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009085 }
9086 }
9087 break;
9088 default:
9089 break;
9090 }
9091 break;
9092 break;
9093 }
9094 } while (cur != NULL);
9095
9096 /*
9097 * If there is some predicate filtering do it now
9098 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009099 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009100 xmlXPathObjectPtr obj2;
9101
9102 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9103 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9104 CHECK_TYPE0(XPATH_NODESET);
9105 obj2 = valuePop(ctxt);
9106 list = obj2->nodesetval;
9107 obj2->nodesetval = NULL;
9108 xmlXPathFreeObject(obj2);
9109 }
9110 if (ret == NULL) {
9111 ret = list;
9112 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009113 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009114 xmlXPathFreeNodeSet(list);
9115 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009116 }
9117 ctxt->context->node = tmp;
9118#ifdef DEBUG_STEP
9119 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009120 "\nExamined %d nodes, found %d nodes at that step\n",
9121 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009122#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009123 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009124 if ((obj->boolval) && (obj->user != NULL)) {
9125 ctxt->value->boolval = 1;
9126 ctxt->value->user = obj->user;
9127 obj->user = NULL;
9128 obj->boolval = 0;
9129 }
9130 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009131 return(t);
9132}
9133
9134/**
9135 * xmlXPathNodeCollectAndTestNth:
9136 * @ctxt: the XPath Parser context
9137 * @op: the XPath precompiled step operation
9138 * @indx: the index to collect
9139 * @first: pointer to the first element in document order
9140 * @last: pointer to the last element in document order
9141 *
9142 * This is the function implementing a step: based on the current list
9143 * of nodes, it builds up a new list, looking at all nodes under that
9144 * axis and selecting them it also do the predicate filtering
9145 *
9146 * Pushes the new NodeSet resulting from the search.
9147 * Returns the number of node traversed
9148 */
9149static int
9150xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9151 xmlXPathStepOpPtr op, int indx,
9152 xmlNodePtr * first, xmlNodePtr * last)
9153{
9154 xmlXPathAxisVal axis = op->value;
9155 xmlXPathTestVal test = op->value2;
9156 xmlXPathTypeVal type = op->value3;
9157 const xmlChar *prefix = op->value4;
9158 const xmlChar *name = op->value5;
9159 const xmlChar *URI = NULL;
9160 int n = 0, t = 0;
9161
9162 int i;
9163 xmlNodeSetPtr list;
9164 xmlXPathTraversalFunction next = NULL;
9165 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9166 xmlNodePtr cur = NULL;
9167 xmlXPathObjectPtr obj;
9168 xmlNodeSetPtr nodelist;
9169 xmlNodePtr tmp;
9170
9171 CHECK_TYPE0(XPATH_NODESET);
9172 obj = valuePop(ctxt);
9173 addNode = xmlXPathNodeSetAdd;
9174 if (prefix != NULL) {
9175 URI = xmlXPathNsLookup(ctxt->context, prefix);
9176 if (URI == NULL)
9177 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9178 }
9179#ifdef DEBUG_STEP_NTH
9180 xmlGenericError(xmlGenericErrorContext, "new step : ");
9181 if (first != NULL) {
9182 if (*first != NULL)
9183 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9184 (*first)->name);
9185 else
9186 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9187 }
9188 if (last != NULL) {
9189 if (*last != NULL)
9190 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9191 (*last)->name);
9192 else
9193 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9194 }
9195#endif
9196 switch (axis) {
9197 case AXIS_ANCESTOR:
9198#ifdef DEBUG_STEP_NTH
9199 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9200#endif
9201 first = NULL;
9202 next = xmlXPathNextAncestor;
9203 break;
9204 case AXIS_ANCESTOR_OR_SELF:
9205#ifdef DEBUG_STEP_NTH
9206 xmlGenericError(xmlGenericErrorContext,
9207 "axis 'ancestors-or-self' ");
9208#endif
9209 first = NULL;
9210 next = xmlXPathNextAncestorOrSelf;
9211 break;
9212 case AXIS_ATTRIBUTE:
9213#ifdef DEBUG_STEP_NTH
9214 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9215#endif
9216 first = NULL;
9217 last = NULL;
9218 next = xmlXPathNextAttribute;
9219 break;
9220 case AXIS_CHILD:
9221#ifdef DEBUG_STEP_NTH
9222 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9223#endif
9224 last = NULL;
9225 next = xmlXPathNextChild;
9226 break;
9227 case AXIS_DESCENDANT:
9228#ifdef DEBUG_STEP_NTH
9229 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9230#endif
9231 last = NULL;
9232 next = xmlXPathNextDescendant;
9233 break;
9234 case AXIS_DESCENDANT_OR_SELF:
9235#ifdef DEBUG_STEP_NTH
9236 xmlGenericError(xmlGenericErrorContext,
9237 "axis 'descendant-or-self' ");
9238#endif
9239 last = NULL;
9240 next = xmlXPathNextDescendantOrSelf;
9241 break;
9242 case AXIS_FOLLOWING:
9243#ifdef DEBUG_STEP_NTH
9244 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9245#endif
9246 last = NULL;
9247 next = xmlXPathNextFollowing;
9248 break;
9249 case AXIS_FOLLOWING_SIBLING:
9250#ifdef DEBUG_STEP_NTH
9251 xmlGenericError(xmlGenericErrorContext,
9252 "axis 'following-siblings' ");
9253#endif
9254 last = NULL;
9255 next = xmlXPathNextFollowingSibling;
9256 break;
9257 case AXIS_NAMESPACE:
9258#ifdef DEBUG_STEP_NTH
9259 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9260#endif
9261 last = NULL;
9262 first = NULL;
9263 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9264 break;
9265 case AXIS_PARENT:
9266#ifdef DEBUG_STEP_NTH
9267 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9268#endif
9269 first = NULL;
9270 next = xmlXPathNextParent;
9271 break;
9272 case AXIS_PRECEDING:
9273#ifdef DEBUG_STEP_NTH
9274 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9275#endif
9276 first = NULL;
9277 next = xmlXPathNextPrecedingInternal;
9278 break;
9279 case AXIS_PRECEDING_SIBLING:
9280#ifdef DEBUG_STEP_NTH
9281 xmlGenericError(xmlGenericErrorContext,
9282 "axis 'preceding-sibling' ");
9283#endif
9284 first = NULL;
9285 next = xmlXPathNextPrecedingSibling;
9286 break;
9287 case AXIS_SELF:
9288#ifdef DEBUG_STEP_NTH
9289 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9290#endif
9291 first = NULL;
9292 last = NULL;
9293 next = xmlXPathNextSelf;
9294 break;
9295 }
9296 if (next == NULL)
9297 return(0);
9298
9299 nodelist = obj->nodesetval;
9300 if (nodelist == NULL) {
9301 xmlXPathFreeObject(obj);
9302 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9303 return(0);
9304 }
9305 addNode = xmlXPathNodeSetAddUnique;
9306#ifdef DEBUG_STEP_NTH
9307 xmlGenericError(xmlGenericErrorContext,
9308 " context contains %d nodes\n", nodelist->nodeNr);
9309 switch (test) {
9310 case NODE_TEST_NONE:
9311 xmlGenericError(xmlGenericErrorContext,
9312 " searching for none !!!\n");
9313 break;
9314 case NODE_TEST_TYPE:
9315 xmlGenericError(xmlGenericErrorContext,
9316 " searching for type %d\n", type);
9317 break;
9318 case NODE_TEST_PI:
9319 xmlGenericError(xmlGenericErrorContext,
9320 " searching for PI !!!\n");
9321 break;
9322 case NODE_TEST_ALL:
9323 xmlGenericError(xmlGenericErrorContext,
9324 " searching for *\n");
9325 break;
9326 case NODE_TEST_NS:
9327 xmlGenericError(xmlGenericErrorContext,
9328 " searching for namespace %s\n",
9329 prefix);
9330 break;
9331 case NODE_TEST_NAME:
9332 xmlGenericError(xmlGenericErrorContext,
9333 " searching for name %s\n", name);
9334 if (prefix != NULL)
9335 xmlGenericError(xmlGenericErrorContext,
9336 " with namespace %s\n", prefix);
9337 break;
9338 }
9339 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9340#endif
9341 /*
9342 * 2.3 Node Tests
9343 * - For the attribute axis, the principal node type is attribute.
9344 * - For the namespace axis, the principal node type is namespace.
9345 * - For other axes, the principal node type is element.
9346 *
9347 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009348 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009349 * select all element children of the context node
9350 */
9351 tmp = ctxt->context->node;
9352 list = xmlXPathNodeSetCreate(NULL);
9353 for (i = 0; i < nodelist->nodeNr; i++) {
9354 ctxt->context->node = nodelist->nodeTab[i];
9355
9356 cur = NULL;
9357 n = 0;
9358 do {
9359 cur = next(ctxt, cur);
9360 if (cur == NULL)
9361 break;
9362 if ((first != NULL) && (*first == cur))
9363 break;
9364 if (((t % 256) == 0) &&
9365 (first != NULL) && (*first != NULL) &&
9366 (xmlXPathCmpNodes(*first, cur) >= 0))
9367 break;
9368 if ((last != NULL) && (*last == cur))
9369 break;
9370 if (((t % 256) == 0) &&
9371 (last != NULL) && (*last != NULL) &&
9372 (xmlXPathCmpNodes(cur, *last) >= 0))
9373 break;
9374 t++;
9375 switch (test) {
9376 case NODE_TEST_NONE:
9377 ctxt->context->node = tmp;
9378 STRANGE return(0);
9379 case NODE_TEST_TYPE:
9380 if ((cur->type == type) ||
9381 ((type == NODE_TYPE_NODE) &&
9382 ((cur->type == XML_DOCUMENT_NODE) ||
9383 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9384 (cur->type == XML_ELEMENT_NODE) ||
9385 (cur->type == XML_PI_NODE) ||
9386 (cur->type == XML_COMMENT_NODE) ||
9387 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +00009388 (cur->type == XML_TEXT_NODE))) ||
9389 ((type == NODE_TYPE_TEXT) &&
9390 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009391 n++;
9392 if (n == indx)
9393 addNode(list, cur);
9394 }
9395 break;
9396 case NODE_TEST_PI:
9397 if (cur->type == XML_PI_NODE) {
9398 if ((name != NULL) &&
9399 (!xmlStrEqual(name, cur->name)))
9400 break;
9401 n++;
9402 if (n == indx)
9403 addNode(list, cur);
9404 }
9405 break;
9406 case NODE_TEST_ALL:
9407 if (axis == AXIS_ATTRIBUTE) {
9408 if (cur->type == XML_ATTRIBUTE_NODE) {
9409 n++;
9410 if (n == indx)
9411 addNode(list, cur);
9412 }
9413 } else if (axis == AXIS_NAMESPACE) {
9414 if (cur->type == XML_NAMESPACE_DECL) {
9415 n++;
9416 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009417 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9418 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009419 }
9420 } else {
9421 if (cur->type == XML_ELEMENT_NODE) {
9422 if (prefix == NULL) {
9423 n++;
9424 if (n == indx)
9425 addNode(list, cur);
9426 } else if ((cur->ns != NULL) &&
9427 (xmlStrEqual(URI, cur->ns->href))) {
9428 n++;
9429 if (n == indx)
9430 addNode(list, cur);
9431 }
9432 }
9433 }
9434 break;
9435 case NODE_TEST_NS:{
9436 TODO;
9437 break;
9438 }
9439 case NODE_TEST_NAME:
9440 switch (cur->type) {
9441 case XML_ELEMENT_NODE:
9442 if (xmlStrEqual(name, cur->name)) {
9443 if (prefix == NULL) {
9444 if (cur->ns == NULL) {
9445 n++;
9446 if (n == indx)
9447 addNode(list, cur);
9448 }
9449 } else {
9450 if ((cur->ns != NULL) &&
9451 (xmlStrEqual(URI,
9452 cur->ns->href))) {
9453 n++;
9454 if (n == indx)
9455 addNode(list, cur);
9456 }
9457 }
9458 }
9459 break;
9460 case XML_ATTRIBUTE_NODE:{
9461 xmlAttrPtr attr = (xmlAttrPtr) cur;
9462
9463 if (xmlStrEqual(name, attr->name)) {
9464 if (prefix == NULL) {
9465 if ((attr->ns == NULL) ||
9466 (attr->ns->prefix == NULL)) {
9467 n++;
9468 if (n == indx)
9469 addNode(list, cur);
9470 }
9471 } else {
9472 if ((attr->ns != NULL) &&
9473 (xmlStrEqual(URI,
9474 attr->ns->
9475 href))) {
9476 n++;
9477 if (n == indx)
9478 addNode(list, cur);
9479 }
9480 }
9481 }
9482 break;
9483 }
9484 case XML_NAMESPACE_DECL:
9485 if (cur->type == XML_NAMESPACE_DECL) {
9486 xmlNsPtr ns = (xmlNsPtr) cur;
9487
9488 if ((ns->prefix != NULL) && (name != NULL)
9489 && (xmlStrEqual(ns->prefix, name))) {
9490 n++;
9491 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009492 xmlXPathNodeSetAddNs(list,
9493 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009494 }
9495 }
9496 break;
9497 default:
9498 break;
9499 }
9500 break;
9501 break;
9502 }
9503 } while (n < indx);
9504 }
9505 ctxt->context->node = tmp;
9506#ifdef DEBUG_STEP_NTH
9507 xmlGenericError(xmlGenericErrorContext,
9508 "\nExamined %d nodes, found %d nodes at that step\n",
9509 t, list->nodeNr);
9510#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009511 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009512 if ((obj->boolval) && (obj->user != NULL)) {
9513 ctxt->value->boolval = 1;
9514 ctxt->value->user = obj->user;
9515 obj->user = NULL;
9516 obj->boolval = 0;
9517 }
9518 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009519 return(t);
9520}
9521
9522/**
9523 * xmlXPathCompOpEvalFirst:
9524 * @ctxt: the XPath parser context with the compiled expression
9525 * @op: an XPath compiled operation
9526 * @first: the first elem found so far
9527 *
9528 * Evaluate the Precompiled XPath operation searching only the first
9529 * element in document order
9530 *
9531 * Returns the number of examined objects.
9532 */
9533static int
9534xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9535 xmlXPathStepOpPtr op, xmlNodePtr * first)
9536{
9537 int total = 0, cur;
9538 xmlXPathCompExprPtr comp;
9539 xmlXPathObjectPtr arg1, arg2;
9540
Daniel Veillard556c6682001-10-06 09:59:51 +00009541 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009542 comp = ctxt->comp;
9543 switch (op->op) {
9544 case XPATH_OP_END:
9545 return (0);
9546 case XPATH_OP_UNION:
9547 total =
9548 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9549 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009550 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009551 if ((ctxt->value != NULL)
9552 && (ctxt->value->type == XPATH_NODESET)
9553 && (ctxt->value->nodesetval != NULL)
9554 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9555 /*
9556 * limit tree traversing to first node in the result
9557 */
9558 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9559 *first = ctxt->value->nodesetval->nodeTab[0];
9560 }
9561 cur =
9562 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9563 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009564 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009565 CHECK_TYPE0(XPATH_NODESET);
9566 arg2 = valuePop(ctxt);
9567
9568 CHECK_TYPE0(XPATH_NODESET);
9569 arg1 = valuePop(ctxt);
9570
9571 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9572 arg2->nodesetval);
9573 valuePush(ctxt, arg1);
9574 xmlXPathFreeObject(arg2);
9575 /* optimizer */
9576 if (total > cur)
9577 xmlXPathCompSwap(op);
9578 return (total + cur);
9579 case XPATH_OP_ROOT:
9580 xmlXPathRoot(ctxt);
9581 return (0);
9582 case XPATH_OP_NODE:
9583 if (op->ch1 != -1)
9584 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009585 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009586 if (op->ch2 != -1)
9587 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009588 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009589 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9590 return (total);
9591 case XPATH_OP_RESET:
9592 if (op->ch1 != -1)
9593 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009594 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009595 if (op->ch2 != -1)
9596 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009597 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009598 ctxt->context->node = NULL;
9599 return (total);
9600 case XPATH_OP_COLLECT:{
9601 if (op->ch1 == -1)
9602 return (total);
9603
9604 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009605 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009606
9607 /*
9608 * Optimization for [n] selection where n is a number
9609 */
9610 if ((op->ch2 != -1) &&
9611 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9612 (comp->steps[op->ch2].ch1 == -1) &&
9613 (comp->steps[op->ch2].ch2 != -1) &&
9614 (comp->steps[comp->steps[op->ch2].ch2].op ==
9615 XPATH_OP_VALUE)) {
9616 xmlXPathObjectPtr val;
9617
9618 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9619 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9620 int indx = (int) val->floatval;
9621
9622 if (val->floatval == (float) indx) {
9623 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9624 first, NULL);
9625 return (total);
9626 }
9627 }
9628 }
9629 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9630 return (total);
9631 }
9632 case XPATH_OP_VALUE:
9633 valuePush(ctxt,
9634 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9635 return (0);
9636 case XPATH_OP_SORT:
9637 if (op->ch1 != -1)
9638 total +=
9639 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9640 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009641 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009642 if ((ctxt->value != NULL)
9643 && (ctxt->value->type == XPATH_NODESET)
9644 && (ctxt->value->nodesetval != NULL))
9645 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9646 return (total);
9647 default:
9648 return (xmlXPathCompOpEval(ctxt, op));
9649 }
9650}
9651
9652/**
9653 * xmlXPathCompOpEvalLast:
9654 * @ctxt: the XPath parser context with the compiled expression
9655 * @op: an XPath compiled operation
9656 * @last: the last elem found so far
9657 *
9658 * Evaluate the Precompiled XPath operation searching only the last
9659 * element in document order
9660 *
9661 * Returns the number of node traversed
9662 */
9663static int
9664xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9665 xmlNodePtr * last)
9666{
9667 int total = 0, cur;
9668 xmlXPathCompExprPtr comp;
9669 xmlXPathObjectPtr arg1, arg2;
9670
Daniel Veillard556c6682001-10-06 09:59:51 +00009671 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009672 comp = ctxt->comp;
9673 switch (op->op) {
9674 case XPATH_OP_END:
9675 return (0);
9676 case XPATH_OP_UNION:
9677 total =
9678 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009679 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009680 if ((ctxt->value != NULL)
9681 && (ctxt->value->type == XPATH_NODESET)
9682 && (ctxt->value->nodesetval != NULL)
9683 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9684 /*
9685 * limit tree traversing to first node in the result
9686 */
9687 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9688 *last =
9689 ctxt->value->nodesetval->nodeTab[ctxt->value->
9690 nodesetval->nodeNr -
9691 1];
9692 }
9693 cur =
9694 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009695 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009696 if ((ctxt->value != NULL)
9697 && (ctxt->value->type == XPATH_NODESET)
9698 && (ctxt->value->nodesetval != NULL)
9699 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9700 }
9701 CHECK_TYPE0(XPATH_NODESET);
9702 arg2 = valuePop(ctxt);
9703
9704 CHECK_TYPE0(XPATH_NODESET);
9705 arg1 = valuePop(ctxt);
9706
9707 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9708 arg2->nodesetval);
9709 valuePush(ctxt, arg1);
9710 xmlXPathFreeObject(arg2);
9711 /* optimizer */
9712 if (total > cur)
9713 xmlXPathCompSwap(op);
9714 return (total + cur);
9715 case XPATH_OP_ROOT:
9716 xmlXPathRoot(ctxt);
9717 return (0);
9718 case XPATH_OP_NODE:
9719 if (op->ch1 != -1)
9720 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009721 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009722 if (op->ch2 != -1)
9723 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009724 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009725 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9726 return (total);
9727 case XPATH_OP_RESET:
9728 if (op->ch1 != -1)
9729 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009730 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009731 if (op->ch2 != -1)
9732 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009733 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009734 ctxt->context->node = NULL;
9735 return (total);
9736 case XPATH_OP_COLLECT:{
9737 if (op->ch1 == -1)
9738 return (0);
9739
9740 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009741 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009742
9743 /*
9744 * Optimization for [n] selection where n is a number
9745 */
9746 if ((op->ch2 != -1) &&
9747 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9748 (comp->steps[op->ch2].ch1 == -1) &&
9749 (comp->steps[op->ch2].ch2 != -1) &&
9750 (comp->steps[comp->steps[op->ch2].ch2].op ==
9751 XPATH_OP_VALUE)) {
9752 xmlXPathObjectPtr val;
9753
9754 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9755 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9756 int indx = (int) val->floatval;
9757
9758 if (val->floatval == (float) indx) {
9759 total +=
9760 xmlXPathNodeCollectAndTestNth(ctxt, op,
9761 indx, NULL,
9762 last);
9763 return (total);
9764 }
9765 }
9766 }
9767 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9768 return (total);
9769 }
9770 case XPATH_OP_VALUE:
9771 valuePush(ctxt,
9772 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9773 return (0);
9774 case XPATH_OP_SORT:
9775 if (op->ch1 != -1)
9776 total +=
9777 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9778 last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009779 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009780 if ((ctxt->value != NULL)
9781 && (ctxt->value->type == XPATH_NODESET)
9782 && (ctxt->value->nodesetval != NULL))
9783 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9784 return (total);
9785 default:
9786 return (xmlXPathCompOpEval(ctxt, op));
9787 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009788}
9789
Owen Taylor3473f882001-02-23 17:55:21 +00009790/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009791 * xmlXPathCompOpEval:
9792 * @ctxt: the XPath parser context with the compiled expression
9793 * @op: an XPath compiled operation
9794 *
9795 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009796 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009797 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009798static int
9799xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9800{
9801 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009802 int equal, ret;
9803 xmlXPathCompExprPtr comp;
9804 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009805 xmlNodePtr bak;
9806 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +00009807 int pp;
William M. Brack692092b2002-06-28 15:01:24 +00009808 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009809
Daniel Veillard556c6682001-10-06 09:59:51 +00009810 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009811 comp = ctxt->comp;
9812 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009813 case XPATH_OP_END:
9814 return (0);
9815 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009816 bakd = ctxt->context->doc;
9817 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009818 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009819 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009820 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009821 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009822 xmlXPathBooleanFunction(ctxt, 1);
9823 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9824 return (total);
9825 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009826 ctxt->context->doc = bakd;
9827 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009828 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009829 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009830 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009831 if (ctxt->error) {
9832 xmlXPathFreeObject(arg2);
9833 return(0);
9834 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009835 xmlXPathBooleanFunction(ctxt, 1);
9836 arg1 = valuePop(ctxt);
9837 arg1->boolval &= arg2->boolval;
9838 valuePush(ctxt, arg1);
9839 xmlXPathFreeObject(arg2);
9840 return (total);
9841 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009842 bakd = ctxt->context->doc;
9843 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009844 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009845 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009846 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009847 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009848 xmlXPathBooleanFunction(ctxt, 1);
9849 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9850 return (total);
9851 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009852 ctxt->context->doc = bakd;
9853 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009854 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009855 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009856 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009857 if (ctxt->error) {
9858 xmlXPathFreeObject(arg2);
9859 return(0);
9860 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009861 xmlXPathBooleanFunction(ctxt, 1);
9862 arg1 = valuePop(ctxt);
9863 arg1->boolval |= arg2->boolval;
9864 valuePush(ctxt, arg1);
9865 xmlXPathFreeObject(arg2);
9866 return (total);
9867 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009868 bakd = ctxt->context->doc;
9869 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009870 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009871 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009872 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009873 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009874 ctxt->context->doc = bakd;
9875 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009876 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009877 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009878 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009879 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +00009880 if (op->value)
9881 equal = xmlXPathEqualValues(ctxt);
9882 else
9883 equal = xmlXPathNotEqualValues(ctxt);
9884 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +00009885 return (total);
9886 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009887 bakd = ctxt->context->doc;
9888 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009889 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009890 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009891 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009892 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009893 ctxt->context->doc = bakd;
9894 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009895 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009896 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009897 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009898 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009899 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
9900 valuePush(ctxt, xmlXPathNewBoolean(ret));
9901 return (total);
9902 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009903 bakd = ctxt->context->doc;
9904 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009905 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009906 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009907 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009908 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009909 if (op->ch2 != -1) {
9910 ctxt->context->doc = bakd;
9911 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009912 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009913 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009914 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009915 }
Daniel Veillard556c6682001-10-06 09:59:51 +00009916 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009917 if (op->value == 0)
9918 xmlXPathSubValues(ctxt);
9919 else if (op->value == 1)
9920 xmlXPathAddValues(ctxt);
9921 else if (op->value == 2)
9922 xmlXPathValueFlipSign(ctxt);
9923 else if (op->value == 3) {
9924 CAST_TO_NUMBER;
9925 CHECK_TYPE0(XPATH_NUMBER);
9926 }
9927 return (total);
9928 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009929 bakd = ctxt->context->doc;
9930 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009931 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009932 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009933 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009934 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009935 ctxt->context->doc = bakd;
9936 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009937 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009938 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009939 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009940 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009941 if (op->value == 0)
9942 xmlXPathMultValues(ctxt);
9943 else if (op->value == 1)
9944 xmlXPathDivValues(ctxt);
9945 else if (op->value == 2)
9946 xmlXPathModValues(ctxt);
9947 return (total);
9948 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009949 bakd = ctxt->context->doc;
9950 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009951 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009952 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009953 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009954 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009955 ctxt->context->doc = bakd;
9956 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009957 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009958 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009959 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009960 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009961 CHECK_TYPE0(XPATH_NODESET);
9962 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009963
Daniel Veillardf06307e2001-07-03 10:35:50 +00009964 CHECK_TYPE0(XPATH_NODESET);
9965 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009966
Daniel Veillardf06307e2001-07-03 10:35:50 +00009967 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9968 arg2->nodesetval);
9969 valuePush(ctxt, arg1);
9970 xmlXPathFreeObject(arg2);
9971 return (total);
9972 case XPATH_OP_ROOT:
9973 xmlXPathRoot(ctxt);
9974 return (total);
9975 case XPATH_OP_NODE:
9976 if (op->ch1 != -1)
9977 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009978 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009979 if (op->ch2 != -1)
9980 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009981 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009982 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9983 return (total);
9984 case XPATH_OP_RESET:
9985 if (op->ch1 != -1)
9986 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009987 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009988 if (op->ch2 != -1)
9989 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009990 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009991 ctxt->context->node = NULL;
9992 return (total);
9993 case XPATH_OP_COLLECT:{
9994 if (op->ch1 == -1)
9995 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009996
Daniel Veillardf06307e2001-07-03 10:35:50 +00009997 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009998 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009999
Daniel Veillardf06307e2001-07-03 10:35:50 +000010000 /*
10001 * Optimization for [n] selection where n is a number
10002 */
10003 if ((op->ch2 != -1) &&
10004 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10005 (comp->steps[op->ch2].ch1 == -1) &&
10006 (comp->steps[op->ch2].ch2 != -1) &&
10007 (comp->steps[comp->steps[op->ch2].ch2].op ==
10008 XPATH_OP_VALUE)) {
10009 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +000010010
Daniel Veillardf06307e2001-07-03 10:35:50 +000010011 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10012 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10013 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010014
Daniel Veillardf06307e2001-07-03 10:35:50 +000010015 if (val->floatval == (float) indx) {
10016 total +=
10017 xmlXPathNodeCollectAndTestNth(ctxt, op,
10018 indx, NULL,
10019 NULL);
10020 return (total);
10021 }
10022 }
10023 }
10024 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
10025 return (total);
10026 }
10027 case XPATH_OP_VALUE:
10028 valuePush(ctxt,
10029 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10030 return (total);
10031 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000010032 xmlXPathObjectPtr val;
10033
Daniel Veillardf06307e2001-07-03 10:35:50 +000010034 if (op->ch1 != -1)
10035 total +=
10036 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010037 if (op->value5 == NULL) {
10038 val = xmlXPathVariableLookup(ctxt->context, op->value4);
10039 if (val == NULL) {
10040 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10041 return(0);
10042 }
10043 valuePush(ctxt, val);
10044 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010045 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010046
Daniel Veillardf06307e2001-07-03 10:35:50 +000010047 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10048 if (URI == NULL) {
10049 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010050 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010051 op->value4, op->value5);
10052 return (total);
10053 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010054 val = xmlXPathVariableLookupNS(ctxt->context,
10055 op->value4, URI);
10056 if (val == NULL) {
10057 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10058 return(0);
10059 }
10060 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010061 }
10062 return (total);
10063 }
10064 case XPATH_OP_FUNCTION:{
10065 xmlXPathFunction func;
10066 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000010067 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010068
10069 if (op->ch1 != -1)
10070 total +=
10071 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010072 if (ctxt->valueNr < op->value) {
10073 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010074 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010075 ctxt->error = XPATH_INVALID_OPERAND;
10076 return (total);
10077 }
10078 for (i = 0; i < op->value; i++)
10079 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10080 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010081 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010082 ctxt->error = XPATH_INVALID_OPERAND;
10083 return (total);
10084 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010085 if (op->cache != NULL)
10086 func = (xmlXPathFunction) op->cache;
10087 else {
10088 const xmlChar *URI = NULL;
10089
10090 if (op->value5 == NULL)
10091 func =
10092 xmlXPathFunctionLookup(ctxt->context,
10093 op->value4);
10094 else {
10095 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10096 if (URI == NULL) {
10097 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010098 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010099 op->value4, op->value5);
10100 return (total);
10101 }
10102 func = xmlXPathFunctionLookupNS(ctxt->context,
10103 op->value4, URI);
10104 }
10105 if (func == NULL) {
10106 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010107 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010108 op->value4);
10109 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010110 }
10111 op->cache = (void *) func;
10112 op->cacheURI = (void *) URI;
10113 }
10114 oldFunc = ctxt->context->function;
10115 oldFuncURI = ctxt->context->functionURI;
10116 ctxt->context->function = op->value4;
10117 ctxt->context->functionURI = op->cacheURI;
10118 func(ctxt, op->value);
10119 ctxt->context->function = oldFunc;
10120 ctxt->context->functionURI = oldFuncURI;
10121 return (total);
10122 }
10123 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000010124 bakd = ctxt->context->doc;
10125 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010126 if (op->ch1 != -1)
10127 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010128 ctxt->context->doc = bakd;
10129 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010130 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010131 if (op->ch2 != -1)
10132 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010133 ctxt->context->doc = bakd;
10134 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010135 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010136 return (total);
10137 case XPATH_OP_PREDICATE:
10138 case XPATH_OP_FILTER:{
10139 xmlXPathObjectPtr res;
10140 xmlXPathObjectPtr obj, tmp;
10141 xmlNodeSetPtr newset = NULL;
10142 xmlNodeSetPtr oldset;
10143 xmlNodePtr oldnode;
10144 int i;
10145
10146 /*
10147 * Optimization for ()[1] selection i.e. the first elem
10148 */
10149 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10150 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10151 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10152 xmlXPathObjectPtr val;
10153
10154 val = comp->steps[op->ch2].value4;
10155 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10156 (val->floatval == 1.0)) {
10157 xmlNodePtr first = NULL;
10158
10159 total +=
10160 xmlXPathCompOpEvalFirst(ctxt,
10161 &comp->steps[op->ch1],
10162 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010163 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010164 /*
10165 * The nodeset should be in document order,
10166 * Keep only the first value
10167 */
10168 if ((ctxt->value != NULL) &&
10169 (ctxt->value->type == XPATH_NODESET) &&
10170 (ctxt->value->nodesetval != NULL) &&
10171 (ctxt->value->nodesetval->nodeNr > 1))
10172 ctxt->value->nodesetval->nodeNr = 1;
10173 return (total);
10174 }
10175 }
10176 /*
10177 * Optimization for ()[last()] selection i.e. the last elem
10178 */
10179 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10180 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10181 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10182 int f = comp->steps[op->ch2].ch1;
10183
10184 if ((f != -1) &&
10185 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10186 (comp->steps[f].value5 == NULL) &&
10187 (comp->steps[f].value == 0) &&
10188 (comp->steps[f].value4 != NULL) &&
10189 (xmlStrEqual
10190 (comp->steps[f].value4, BAD_CAST "last"))) {
10191 xmlNodePtr last = NULL;
10192
10193 total +=
10194 xmlXPathCompOpEvalLast(ctxt,
10195 &comp->steps[op->ch1],
10196 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010197 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010198 /*
10199 * The nodeset should be in document order,
10200 * Keep only the last value
10201 */
10202 if ((ctxt->value != NULL) &&
10203 (ctxt->value->type == XPATH_NODESET) &&
10204 (ctxt->value->nodesetval != NULL) &&
10205 (ctxt->value->nodesetval->nodeTab != NULL) &&
10206 (ctxt->value->nodesetval->nodeNr > 1)) {
10207 ctxt->value->nodesetval->nodeTab[0] =
10208 ctxt->value->nodesetval->nodeTab[ctxt->
10209 value->
10210 nodesetval->
10211 nodeNr -
10212 1];
10213 ctxt->value->nodesetval->nodeNr = 1;
10214 }
10215 return (total);
10216 }
10217 }
10218
10219 if (op->ch1 != -1)
10220 total +=
10221 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010222 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010223 if (op->ch2 == -1)
10224 return (total);
10225 if (ctxt->value == NULL)
10226 return (total);
10227
10228 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010229
10230#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010231 /*
10232 * Hum are we filtering the result of an XPointer expression
10233 */
10234 if (ctxt->value->type == XPATH_LOCATIONSET) {
10235 xmlLocationSetPtr newlocset = NULL;
10236 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010237
Daniel Veillardf06307e2001-07-03 10:35:50 +000010238 /*
10239 * Extract the old locset, and then evaluate the result of the
10240 * expression for all the element in the locset. use it to grow
10241 * up a new locset.
10242 */
10243 CHECK_TYPE0(XPATH_LOCATIONSET);
10244 obj = valuePop(ctxt);
10245 oldlocset = obj->user;
10246 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010247
Daniel Veillardf06307e2001-07-03 10:35:50 +000010248 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10249 ctxt->context->contextSize = 0;
10250 ctxt->context->proximityPosition = 0;
10251 if (op->ch2 != -1)
10252 total +=
10253 xmlXPathCompOpEval(ctxt,
10254 &comp->steps[op->ch2]);
10255 res = valuePop(ctxt);
10256 if (res != NULL)
10257 xmlXPathFreeObject(res);
10258 valuePush(ctxt, obj);
10259 CHECK_ERROR0;
10260 return (total);
10261 }
10262 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010263
Daniel Veillardf06307e2001-07-03 10:35:50 +000010264 for (i = 0; i < oldlocset->locNr; i++) {
10265 /*
10266 * Run the evaluation with a node list made of a
10267 * single item in the nodelocset.
10268 */
10269 ctxt->context->node = oldlocset->locTab[i]->user;
10270 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10271 valuePush(ctxt, tmp);
10272 ctxt->context->contextSize = oldlocset->locNr;
10273 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010274
Daniel Veillardf06307e2001-07-03 10:35:50 +000010275 if (op->ch2 != -1)
10276 total +=
10277 xmlXPathCompOpEval(ctxt,
10278 &comp->steps[op->ch2]);
10279 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010280
Daniel Veillardf06307e2001-07-03 10:35:50 +000010281 /*
10282 * The result of the evaluation need to be tested to
10283 * decided whether the filter succeeded or not
10284 */
10285 res = valuePop(ctxt);
10286 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10287 xmlXPtrLocationSetAdd(newlocset,
10288 xmlXPathObjectCopy
10289 (oldlocset->locTab[i]));
10290 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010291
Daniel Veillardf06307e2001-07-03 10:35:50 +000010292 /*
10293 * Cleanup
10294 */
10295 if (res != NULL)
10296 xmlXPathFreeObject(res);
10297 if (ctxt->value == tmp) {
10298 res = valuePop(ctxt);
10299 xmlXPathFreeObject(res);
10300 }
10301
10302 ctxt->context->node = NULL;
10303 }
10304
10305 /*
10306 * The result is used as the new evaluation locset.
10307 */
10308 xmlXPathFreeObject(obj);
10309 ctxt->context->node = NULL;
10310 ctxt->context->contextSize = -1;
10311 ctxt->context->proximityPosition = -1;
10312 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10313 ctxt->context->node = oldnode;
10314 return (total);
10315 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010316#endif /* LIBXML_XPTR_ENABLED */
10317
Daniel Veillardf06307e2001-07-03 10:35:50 +000010318 /*
10319 * Extract the old set, and then evaluate the result of the
10320 * expression for all the element in the set. use it to grow
10321 * up a new set.
10322 */
10323 CHECK_TYPE0(XPATH_NODESET);
10324 obj = valuePop(ctxt);
10325 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010326
Daniel Veillardf06307e2001-07-03 10:35:50 +000010327 oldnode = ctxt->context->node;
10328 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010329
Daniel Veillardf06307e2001-07-03 10:35:50 +000010330 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10331 ctxt->context->contextSize = 0;
10332 ctxt->context->proximityPosition = 0;
10333 if (op->ch2 != -1)
10334 total +=
10335 xmlXPathCompOpEval(ctxt,
10336 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010337 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010338 res = valuePop(ctxt);
10339 if (res != NULL)
10340 xmlXPathFreeObject(res);
10341 valuePush(ctxt, obj);
10342 ctxt->context->node = oldnode;
10343 CHECK_ERROR0;
10344 } else {
10345 /*
10346 * Initialize the new set.
10347 */
10348 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010349
Daniel Veillardf06307e2001-07-03 10:35:50 +000010350 for (i = 0; i < oldset->nodeNr; i++) {
10351 /*
10352 * Run the evaluation with a node list made of
10353 * a single item in the nodeset.
10354 */
10355 ctxt->context->node = oldset->nodeTab[i];
10356 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10357 valuePush(ctxt, tmp);
10358 ctxt->context->contextSize = oldset->nodeNr;
10359 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010360
Daniel Veillardf06307e2001-07-03 10:35:50 +000010361 if (op->ch2 != -1)
10362 total +=
10363 xmlXPathCompOpEval(ctxt,
10364 &comp->steps[op->ch2]);
10365 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010366
Daniel Veillardf06307e2001-07-03 10:35:50 +000010367 /*
10368 * The result of the evaluation need to be tested to
10369 * decided whether the filter succeeded or not
10370 */
10371 res = valuePop(ctxt);
10372 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10373 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10374 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010375
Daniel Veillardf06307e2001-07-03 10:35:50 +000010376 /*
10377 * Cleanup
10378 */
10379 if (res != NULL)
10380 xmlXPathFreeObject(res);
10381 if (ctxt->value == tmp) {
10382 res = valuePop(ctxt);
10383 xmlXPathFreeObject(res);
10384 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010385
Daniel Veillardf06307e2001-07-03 10:35:50 +000010386 ctxt->context->node = NULL;
10387 }
10388
10389 /*
10390 * The result is used as the new evaluation set.
10391 */
10392 xmlXPathFreeObject(obj);
10393 ctxt->context->node = NULL;
10394 ctxt->context->contextSize = -1;
10395 ctxt->context->proximityPosition = -1;
10396 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10397 }
10398 ctxt->context->node = oldnode;
10399 return (total);
10400 }
10401 case XPATH_OP_SORT:
10402 if (op->ch1 != -1)
10403 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010404 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010405 if ((ctxt->value != NULL) &&
10406 (ctxt->value->type == XPATH_NODESET) &&
10407 (ctxt->value->nodesetval != NULL))
10408 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10409 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010410#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010411 case XPATH_OP_RANGETO:{
10412 xmlXPathObjectPtr range;
10413 xmlXPathObjectPtr res, obj;
10414 xmlXPathObjectPtr tmp;
10415 xmlLocationSetPtr newset = NULL;
10416 xmlNodeSetPtr oldset;
10417 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010418
Daniel Veillardf06307e2001-07-03 10:35:50 +000010419 if (op->ch1 != -1)
10420 total +=
10421 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10422 if (op->ch2 == -1)
10423 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010424
Daniel Veillardf06307e2001-07-03 10:35:50 +000010425 CHECK_TYPE0(XPATH_NODESET);
10426 obj = valuePop(ctxt);
10427 oldset = obj->nodesetval;
10428 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010429
Daniel Veillardf06307e2001-07-03 10:35:50 +000010430 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010431
Daniel Veillardf06307e2001-07-03 10:35:50 +000010432 if (oldset != NULL) {
10433 for (i = 0; i < oldset->nodeNr; i++) {
10434 /*
10435 * Run the evaluation with a node list made of a single item
10436 * in the nodeset.
10437 */
10438 ctxt->context->node = oldset->nodeTab[i];
10439 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10440 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010441
Daniel Veillardf06307e2001-07-03 10:35:50 +000010442 if (op->ch2 != -1)
10443 total +=
10444 xmlXPathCompOpEval(ctxt,
10445 &comp->steps[op->ch2]);
10446 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010447
Daniel Veillardf06307e2001-07-03 10:35:50 +000010448 /*
10449 * The result of the evaluation need to be tested to
10450 * decided whether the filter succeeded or not
10451 */
10452 res = valuePop(ctxt);
10453 range =
10454 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10455 res);
10456 if (range != NULL) {
10457 xmlXPtrLocationSetAdd(newset, range);
10458 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010459
Daniel Veillardf06307e2001-07-03 10:35:50 +000010460 /*
10461 * Cleanup
10462 */
10463 if (res != NULL)
10464 xmlXPathFreeObject(res);
10465 if (ctxt->value == tmp) {
10466 res = valuePop(ctxt);
10467 xmlXPathFreeObject(res);
10468 }
10469
10470 ctxt->context->node = NULL;
10471 }
10472 }
10473
10474 /*
10475 * The result is used as the new evaluation set.
10476 */
10477 xmlXPathFreeObject(obj);
10478 ctxt->context->node = NULL;
10479 ctxt->context->contextSize = -1;
10480 ctxt->context->proximityPosition = -1;
10481 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
10482 return (total);
10483 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010484#endif /* LIBXML_XPTR_ENABLED */
10485 }
10486 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010487 "XPath: unknown precompiled operation %d\n", op->op);
10488 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010489}
10490
10491/**
10492 * xmlXPathRunEval:
10493 * @ctxt: the XPath parser context with the compiled expression
10494 *
10495 * Evaluate the Precompiled XPath expression in the given context.
10496 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010497static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010498xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10499 xmlXPathCompExprPtr comp;
10500
10501 if ((ctxt == NULL) || (ctxt->comp == NULL))
10502 return;
10503
10504 if (ctxt->valueTab == NULL) {
10505 /* Allocate the value stack */
10506 ctxt->valueTab = (xmlXPathObjectPtr *)
10507 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10508 if (ctxt->valueTab == NULL) {
10509 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010510 }
10511 ctxt->valueNr = 0;
10512 ctxt->valueMax = 10;
10513 ctxt->value = NULL;
10514 }
10515 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000010516 if(comp->last < 0) {
10517 xmlGenericError(xmlGenericErrorContext,
10518 "xmlXPathRunEval: last is less than zero\n");
10519 return;
10520 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010521 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10522}
10523
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010524/************************************************************************
10525 * *
10526 * Public interfaces *
10527 * *
10528 ************************************************************************/
10529
10530/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010531 * xmlXPathEvalPredicate:
10532 * @ctxt: the XPath context
10533 * @res: the Predicate Expression evaluation result
10534 *
10535 * Evaluate a predicate result for the current node.
10536 * A PredicateExpr is evaluated by evaluating the Expr and converting
10537 * the result to a boolean. If the result is a number, the result will
10538 * be converted to true if the number is equal to the position of the
10539 * context node in the context node list (as returned by the position
10540 * function) and will be converted to false otherwise; if the result
10541 * is not a number, then the result will be converted as if by a call
10542 * to the boolean function.
10543 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010544 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010545 */
10546int
10547xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
10548 if (res == NULL) return(0);
10549 switch (res->type) {
10550 case XPATH_BOOLEAN:
10551 return(res->boolval);
10552 case XPATH_NUMBER:
10553 return(res->floatval == ctxt->proximityPosition);
10554 case XPATH_NODESET:
10555 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010556 if (res->nodesetval == NULL)
10557 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010558 return(res->nodesetval->nodeNr != 0);
10559 case XPATH_STRING:
10560 return((res->stringval != NULL) &&
10561 (xmlStrlen(res->stringval) != 0));
10562 default:
10563 STRANGE
10564 }
10565 return(0);
10566}
10567
10568/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010569 * xmlXPathEvaluatePredicateResult:
10570 * @ctxt: the XPath Parser context
10571 * @res: the Predicate Expression evaluation result
10572 *
10573 * Evaluate a predicate result for the current node.
10574 * A PredicateExpr is evaluated by evaluating the Expr and converting
10575 * the result to a boolean. If the result is a number, the result will
10576 * be converted to true if the number is equal to the position of the
10577 * context node in the context node list (as returned by the position
10578 * function) and will be converted to false otherwise; if the result
10579 * is not a number, then the result will be converted as if by a call
10580 * to the boolean function.
10581 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010582 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010583 */
10584int
10585xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10586 xmlXPathObjectPtr res) {
10587 if (res == NULL) return(0);
10588 switch (res->type) {
10589 case XPATH_BOOLEAN:
10590 return(res->boolval);
10591 case XPATH_NUMBER:
10592 return(res->floatval == ctxt->context->proximityPosition);
10593 case XPATH_NODESET:
10594 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000010595 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000010596 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010597 return(res->nodesetval->nodeNr != 0);
10598 case XPATH_STRING:
10599 return((res->stringval != NULL) &&
10600 (xmlStrlen(res->stringval) != 0));
10601 default:
10602 STRANGE
10603 }
10604 return(0);
10605}
10606
10607/**
10608 * xmlXPathCompile:
10609 * @str: the XPath expression
10610 *
10611 * Compile an XPath expression
10612 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000010613 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010614 * the caller has to free the object.
10615 */
10616xmlXPathCompExprPtr
10617xmlXPathCompile(const xmlChar *str) {
10618 xmlXPathParserContextPtr ctxt;
10619 xmlXPathCompExprPtr comp;
10620
10621 xmlXPathInit();
10622
10623 ctxt = xmlXPathNewParserContext(str, NULL);
10624 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010625
Daniel Veillard40af6492001-04-22 08:50:55 +000010626 if (*ctxt->cur != 0) {
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010627 /*
10628 * aleksey: in some cases this line prints *second* error message
10629 * (see bug #78858) and probably this should be fixed.
10630 * However, we are not sure that all error messages are printed
10631 * out in other places. It's not critical so we leave it as-is for now
10632 */
Daniel Veillard40af6492001-04-22 08:50:55 +000010633 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10634 comp = NULL;
10635 } else {
10636 comp = ctxt->comp;
10637 ctxt->comp = NULL;
10638 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010639 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010640 if (comp != NULL) {
Daniel Veillardceb09b92002-10-04 11:46:37 +000010641 comp->expr = xmlStrdup(str);
10642#ifdef DEBUG_EVAL_COUNTS
Daniel Veillardf06307e2001-07-03 10:35:50 +000010643 comp->string = xmlStrdup(str);
10644 comp->nb = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010645#endif
Daniel Veillardceb09b92002-10-04 11:46:37 +000010646 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010647 return(comp);
10648}
10649
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010650/**
10651 * xmlXPathCompiledEval:
10652 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000010653 * @ctx: the XPath context
10654 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010655 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000010656 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010657 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000010658 * the caller has to free the object.
10659 */
10660xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010661xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000010662 xmlXPathParserContextPtr ctxt;
10663 xmlXPathObjectPtr res, tmp, init = NULL;
10664 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000010665#ifndef LIBXML_THREAD_ENABLED
10666 static int reentance = 0;
10667#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010668
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010669 if ((comp == NULL) || (ctx == NULL))
10670 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010671 xmlXPathInit();
10672
10673 CHECK_CONTEXT(ctx)
10674
Daniel Veillard81463942001-10-16 12:34:39 +000010675#ifndef LIBXML_THREAD_ENABLED
10676 reentance++;
10677 if (reentance > 1)
10678 xmlXPathDisableOptimizer = 1;
10679#endif
10680
Daniel Veillardf06307e2001-07-03 10:35:50 +000010681#ifdef DEBUG_EVAL_COUNTS
10682 comp->nb++;
10683 if ((comp->string != NULL) && (comp->nb > 100)) {
10684 fprintf(stderr, "100 x %s\n", comp->string);
10685 comp->nb = 0;
10686 }
10687#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010688 ctxt = xmlXPathCompParserContext(comp, ctx);
10689 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010690
10691 if (ctxt->value == NULL) {
10692 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010693 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000010694 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000010695 } else {
10696 res = valuePop(ctxt);
10697 }
10698
Daniel Veillardf06307e2001-07-03 10:35:50 +000010699
Owen Taylor3473f882001-02-23 17:55:21 +000010700 do {
10701 tmp = valuePop(ctxt);
10702 if (tmp != NULL) {
10703 if (tmp != init)
10704 stack++;
10705 xmlXPathFreeObject(tmp);
10706 }
10707 } while (tmp != NULL);
10708 if ((stack != 0) && (res != NULL)) {
10709 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010710 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000010711 stack);
10712 }
10713 if (ctxt->error != XPATH_EXPRESSION_OK) {
10714 xmlXPathFreeObject(res);
10715 res = NULL;
10716 }
10717
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010718
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010719 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010720 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000010721#ifndef LIBXML_THREAD_ENABLED
10722 reentance--;
10723#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010724 return(res);
10725}
10726
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010727/**
10728 * xmlXPathEvalExpr:
10729 * @ctxt: the XPath Parser context
10730 *
10731 * Parse and evaluate an XPath expression in the given context,
10732 * then push the result on the context stack
10733 */
10734void
10735xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
10736 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010737 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010738 xmlXPathRunEval(ctxt);
10739}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010740
10741/**
10742 * xmlXPathEval:
10743 * @str: the XPath expression
10744 * @ctx: the XPath context
10745 *
10746 * Evaluate the XPath Location Path in the given context.
10747 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010748 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010749 * the caller has to free the object.
10750 */
10751xmlXPathObjectPtr
10752xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
10753 xmlXPathParserContextPtr ctxt;
10754 xmlXPathObjectPtr res, tmp, init = NULL;
10755 int stack = 0;
10756
10757 xmlXPathInit();
10758
10759 CHECK_CONTEXT(ctx)
10760
10761 ctxt = xmlXPathNewParserContext(str, ctx);
10762 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010763
10764 if (ctxt->value == NULL) {
10765 xmlGenericError(xmlGenericErrorContext,
10766 "xmlXPathEval: evaluation failed\n");
10767 res = NULL;
10768 } else if (*ctxt->cur != 0) {
10769 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10770 res = NULL;
10771 } else {
10772 res = valuePop(ctxt);
10773 }
10774
10775 do {
10776 tmp = valuePop(ctxt);
10777 if (tmp != NULL) {
10778 if (tmp != init)
10779 stack++;
10780 xmlXPathFreeObject(tmp);
10781 }
10782 } while (tmp != NULL);
10783 if ((stack != 0) && (res != NULL)) {
10784 xmlGenericError(xmlGenericErrorContext,
10785 "xmlXPathEval: %d object left on the stack\n",
10786 stack);
10787 }
10788 if (ctxt->error != XPATH_EXPRESSION_OK) {
10789 xmlXPathFreeObject(res);
10790 res = NULL;
10791 }
10792
Owen Taylor3473f882001-02-23 17:55:21 +000010793 xmlXPathFreeParserContext(ctxt);
10794 return(res);
10795}
10796
10797/**
10798 * xmlXPathEvalExpression:
10799 * @str: the XPath expression
10800 * @ctxt: the XPath context
10801 *
10802 * Evaluate the XPath expression in the given context.
10803 *
10804 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
10805 * the caller has to free the object.
10806 */
10807xmlXPathObjectPtr
10808xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
10809 xmlXPathParserContextPtr pctxt;
10810 xmlXPathObjectPtr res, tmp;
10811 int stack = 0;
10812
10813 xmlXPathInit();
10814
10815 CHECK_CONTEXT(ctxt)
10816
10817 pctxt = xmlXPathNewParserContext(str, ctxt);
10818 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010819
10820 if (*pctxt->cur != 0) {
10821 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10822 res = NULL;
10823 } else {
10824 res = valuePop(pctxt);
10825 }
10826 do {
10827 tmp = valuePop(pctxt);
10828 if (tmp != NULL) {
10829 xmlXPathFreeObject(tmp);
10830 stack++;
10831 }
10832 } while (tmp != NULL);
10833 if ((stack != 0) && (res != NULL)) {
10834 xmlGenericError(xmlGenericErrorContext,
10835 "xmlXPathEvalExpression: %d object left on the stack\n",
10836 stack);
10837 }
10838 xmlXPathFreeParserContext(pctxt);
10839 return(res);
10840}
10841
Daniel Veillard42766c02002-08-22 20:52:17 +000010842/************************************************************************
10843 * *
10844 * Extra functions not pertaining to the XPath spec *
10845 * *
10846 ************************************************************************/
10847/**
10848 * xmlXPathEscapeUriFunction:
10849 * @ctxt: the XPath Parser context
10850 * @nargs: the number of arguments
10851 *
10852 * Implement the escape-uri() XPath function
10853 * string escape-uri(string $str, bool $escape-reserved)
10854 *
10855 * This function applies the URI escaping rules defined in section 2 of [RFC
10856 * 2396] to the string supplied as $uri-part, which typically represents all
10857 * or part of a URI. The effect of the function is to replace any special
10858 * character in the string by an escape sequence of the form %xx%yy...,
10859 * where xxyy... is the hexadecimal representation of the octets used to
10860 * represent the character in UTF-8.
10861 *
10862 * The set of characters that are escaped depends on the setting of the
10863 * boolean argument $escape-reserved.
10864 *
10865 * If $escape-reserved is true, all characters are escaped other than lower
10866 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
10867 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
10868 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
10869 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
10870 * A-F).
10871 *
10872 * If $escape-reserved is false, the behavior differs in that characters
10873 * referred to in [RFC 2396] as reserved characters are not escaped. These
10874 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
10875 *
10876 * [RFC 2396] does not define whether escaped URIs should use lower case or
10877 * upper case for hexadecimal digits. To ensure that escaped URIs can be
10878 * compared using string comparison functions, this function must always use
10879 * the upper-case letters A-F.
10880 *
10881 * Generally, $escape-reserved should be set to true when escaping a string
10882 * that is to form a single part of a URI, and to false when escaping an
10883 * entire URI or URI reference.
10884 *
10885 * In the case of non-ascii characters, the string is encoded according to
10886 * utf-8 and then converted according to RFC 2396.
10887 *
10888 * Examples
10889 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
10890 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
10891 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
10892 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
10893 *
10894 */
Daniel Veillard118aed72002-09-24 14:13:13 +000010895static void
Daniel Veillard42766c02002-08-22 20:52:17 +000010896xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
10897 xmlXPathObjectPtr str;
10898 int escape_reserved;
10899 xmlBufferPtr target;
10900 xmlChar *cptr;
10901 xmlChar escape[4];
10902
10903 CHECK_ARITY(2);
10904
10905 escape_reserved = xmlXPathPopBoolean(ctxt);
10906
10907 CAST_TO_STRING;
10908 str = valuePop(ctxt);
10909
10910 target = xmlBufferCreate();
10911
10912 escape[0] = '%';
10913 escape[3] = 0;
10914
10915 if (target) {
10916 for (cptr = str->stringval; *cptr; cptr++) {
10917 if ((*cptr >= 'A' && *cptr <= 'Z') ||
10918 (*cptr >= 'a' && *cptr <= 'z') ||
10919 (*cptr >= '0' && *cptr <= '9') ||
10920 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
10921 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
10922 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
10923 (*cptr == '%' &&
10924 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
10925 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
10926 (cptr[1] >= '0' && cptr[1] <= '9')) &&
10927 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
10928 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
10929 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
10930 (!escape_reserved &&
10931 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
10932 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
10933 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
10934 *cptr == ','))) {
10935 xmlBufferAdd(target, cptr, 1);
10936 } else {
10937 if ((*cptr >> 4) < 10)
10938 escape[1] = '0' + (*cptr >> 4);
10939 else
10940 escape[1] = 'A' - 10 + (*cptr >> 4);
10941 if ((*cptr & 0xF) < 10)
10942 escape[2] = '0' + (*cptr & 0xF);
10943 else
10944 escape[2] = 'A' - 10 + (*cptr & 0xF);
10945
10946 xmlBufferAdd(target, &escape[0], 3);
10947 }
10948 }
10949 }
10950 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
10951 xmlBufferFree(target);
10952 xmlXPathFreeObject(str);
10953}
10954
Owen Taylor3473f882001-02-23 17:55:21 +000010955/**
10956 * xmlXPathRegisterAllFunctions:
10957 * @ctxt: the XPath context
10958 *
10959 * Registers all default XPath functions in this context
10960 */
10961void
10962xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
10963{
10964 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
10965 xmlXPathBooleanFunction);
10966 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
10967 xmlXPathCeilingFunction);
10968 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
10969 xmlXPathCountFunction);
10970 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
10971 xmlXPathConcatFunction);
10972 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
10973 xmlXPathContainsFunction);
10974 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
10975 xmlXPathIdFunction);
10976 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
10977 xmlXPathFalseFunction);
10978 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
10979 xmlXPathFloorFunction);
10980 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
10981 xmlXPathLastFunction);
10982 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
10983 xmlXPathLangFunction);
10984 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
10985 xmlXPathLocalNameFunction);
10986 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
10987 xmlXPathNotFunction);
10988 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
10989 xmlXPathNameFunction);
10990 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
10991 xmlXPathNamespaceURIFunction);
10992 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
10993 xmlXPathNormalizeFunction);
10994 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
10995 xmlXPathNumberFunction);
10996 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
10997 xmlXPathPositionFunction);
10998 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
10999 xmlXPathRoundFunction);
11000 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
11001 xmlXPathStringFunction);
11002 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
11003 xmlXPathStringLengthFunction);
11004 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
11005 xmlXPathStartsWithFunction);
11006 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
11007 xmlXPathSubstringFunction);
11008 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
11009 xmlXPathSubstringBeforeFunction);
11010 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
11011 xmlXPathSubstringAfterFunction);
11012 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
11013 xmlXPathSumFunction);
11014 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
11015 xmlXPathTrueFunction);
11016 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
11017 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000011018
11019 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
11020 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
11021 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000011022}
11023
11024#endif /* LIBXML_XPATH_ENABLED */