blob: 305bccf335f7b742680f84a194c8ee6482a64f05 [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
56/* #define DEBUG */
57/* #define DEBUG_STEP */
Daniel Veillardf06307e2001-07-03 10:35:50 +000058/* #define DEBUG_STEP_NTH */
Owen Taylor3473f882001-02-23 17:55:21 +000059/* #define DEBUG_EXPR */
Daniel Veillardf06307e2001-07-03 10:35:50 +000060/* #define DEBUG_EVAL_COUNTS */
Owen Taylor3473f882001-02-23 17:55:21 +000061
Daniel Veillard20ee8c02001-10-05 09:18:14 +000062static xmlNs xmlXPathXMLNamespaceStruct = {
63 NULL,
64 XML_NAMESPACE_DECL,
65 XML_XML_NAMESPACE,
Daniel Veillard118aed72002-09-24 14:13:13 +000066 BAD_CAST "xml",
67 NULL
Daniel Veillard20ee8c02001-10-05 09:18:14 +000068};
69static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
Daniel Veillardda423da2002-04-10 19:25:38 +000070#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +000071/*
72 * Optimizer is disabled only when threaded apps are detected while
73 * the library ain't compiled for thread safety.
74 */
75static int xmlXPathDisableOptimizer = 0;
76#endif
Daniel Veillard20ee8c02001-10-05 09:18:14 +000077
Daniel Veillard9e7160d2001-03-18 23:17:47 +000078/************************************************************************
79 * *
80 * Floating point stuff *
81 * *
82 ************************************************************************/
83
Daniel Veillardc0631a62001-09-20 13:56:06 +000084#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +000085#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +000086#endif
Daniel Veillardcda96922001-08-21 10:56:31 +000087#include "trionan.c"
88
Owen Taylor3473f882001-02-23 17:55:21 +000089/*
Owen Taylor3473f882001-02-23 17:55:21 +000090 * The lack of portability of this section of the libc is annoying !
91 */
92double xmlXPathNAN = 0;
93double xmlXPathPINF = 1;
94double xmlXPathNINF = -1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +000095double xmlXPathNZERO = 0;
Daniel Veillard20ee8c02001-10-05 09:18:14 +000096static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000097
Owen Taylor3473f882001-02-23 17:55:21 +000098/**
99 * xmlXPathInit:
100 *
101 * Initialize the XPath environment
102 */
103void
104xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000105 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +0000106
Bjorn Reese45029602001-08-21 09:23:53 +0000107 xmlXPathPINF = trio_pinf();
108 xmlXPathNINF = trio_ninf();
109 xmlXPathNAN = trio_nan();
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000110 xmlXPathNZERO = trio_nzero();
Owen Taylor3473f882001-02-23 17:55:21 +0000111
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000112 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000113}
114
Daniel Veillardcda96922001-08-21 10:56:31 +0000115/**
116 * xmlXPathIsNaN:
117 * @val: a double value
118 *
119 * Provides a portable isnan() function to detect whether a double
120 * is a NotaNumber. Based on trio code
121 * http://sourceforge.net/projects/ctrio/
122 *
123 * Returns 1 if the value is a NaN, 0 otherwise
124 */
125int
126xmlXPathIsNaN(double val) {
127 return(trio_isnan(val));
128}
129
130/**
131 * xmlXPathIsInf:
132 * @val: a double value
133 *
134 * Provides a portable isinf() function to detect whether a double
135 * is a +Infinite or -Infinite. Based on trio code
136 * http://sourceforge.net/projects/ctrio/
137 *
138 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
139 */
140int
141xmlXPathIsInf(double val) {
142 return(trio_isinf(val));
143}
144
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000145/**
146 * xmlXPathGetSign:
147 * @val: a double value
148 *
149 * Provides a portable function to detect the sign of a double
150 * Modified from trio code
151 * http://sourceforge.net/projects/ctrio/
152 *
153 * Returns 1 if the value is Negative, 0 if positive
154 */
Daniel Veillard21458c82002-03-27 16:12:22 +0000155static int
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000156xmlXPathGetSign(double val) {
Daniel Veillard21458c82002-03-27 16:12:22 +0000157 return(trio_signbit(val));
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000158}
159
160
Owen Taylor3473f882001-02-23 17:55:21 +0000161/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000162 * *
163 * Parser Types *
164 * *
165 ************************************************************************/
166
167/*
168 * Types are private:
169 */
170
171typedef enum {
172 XPATH_OP_END=0,
173 XPATH_OP_AND,
174 XPATH_OP_OR,
175 XPATH_OP_EQUAL,
176 XPATH_OP_CMP,
177 XPATH_OP_PLUS,
178 XPATH_OP_MULT,
179 XPATH_OP_UNION,
180 XPATH_OP_ROOT,
181 XPATH_OP_NODE,
182 XPATH_OP_RESET,
183 XPATH_OP_COLLECT,
184 XPATH_OP_VALUE,
185 XPATH_OP_VARIABLE,
186 XPATH_OP_FUNCTION,
187 XPATH_OP_ARG,
188 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000189 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000190 XPATH_OP_SORT
191#ifdef LIBXML_XPTR_ENABLED
192 ,XPATH_OP_RANGETO
193#endif
194} xmlXPathOp;
195
196typedef enum {
197 AXIS_ANCESTOR = 1,
198 AXIS_ANCESTOR_OR_SELF,
199 AXIS_ATTRIBUTE,
200 AXIS_CHILD,
201 AXIS_DESCENDANT,
202 AXIS_DESCENDANT_OR_SELF,
203 AXIS_FOLLOWING,
204 AXIS_FOLLOWING_SIBLING,
205 AXIS_NAMESPACE,
206 AXIS_PARENT,
207 AXIS_PRECEDING,
208 AXIS_PRECEDING_SIBLING,
209 AXIS_SELF
210} xmlXPathAxisVal;
211
212typedef enum {
213 NODE_TEST_NONE = 0,
214 NODE_TEST_TYPE = 1,
215 NODE_TEST_PI = 2,
216 NODE_TEST_ALL = 3,
217 NODE_TEST_NS = 4,
218 NODE_TEST_NAME = 5
219} xmlXPathTestVal;
220
221typedef enum {
222 NODE_TYPE_NODE = 0,
223 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
224 NODE_TYPE_TEXT = XML_TEXT_NODE,
225 NODE_TYPE_PI = XML_PI_NODE
226} xmlXPathTypeVal;
227
228
229typedef struct _xmlXPathStepOp xmlXPathStepOp;
230typedef xmlXPathStepOp *xmlXPathStepOpPtr;
231struct _xmlXPathStepOp {
232 xmlXPathOp op;
233 int ch1;
234 int ch2;
235 int value;
236 int value2;
237 int value3;
238 void *value4;
239 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000240 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000241 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000242};
243
244struct _xmlXPathCompExpr {
245 int nbStep;
246 int maxStep;
247 xmlXPathStepOp *steps; /* ops for computation */
248 int last;
Daniel Veillard118aed72002-09-24 14:13:13 +0000249 xmlChar *expr;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000250#ifdef DEBUG_EVAL_COUNTS
251 int nb;
252 xmlChar *string;
253#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000254};
255
256/************************************************************************
257 * *
258 * Parser Type functions *
259 * *
260 ************************************************************************/
261
262/**
263 * xmlXPathNewCompExpr:
264 *
265 * Create a new Xpath component
266 *
267 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
268 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000269static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000270xmlXPathNewCompExpr(void) {
271 xmlXPathCompExprPtr cur;
272
273 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
274 if (cur == NULL) {
275 xmlGenericError(xmlGenericErrorContext,
276 "xmlXPathNewCompExpr : malloc failed\n");
277 return(NULL);
278 }
279 memset(cur, 0, sizeof(xmlXPathCompExpr));
280 cur->maxStep = 10;
281 cur->nbStep = 0;
282 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
283 sizeof(xmlXPathStepOp));
284 if (cur->steps == NULL) {
285 xmlGenericError(xmlGenericErrorContext,
286 "xmlXPathNewCompExpr : malloc failed\n");
287 xmlFree(cur);
288 return(NULL);
289 }
290 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
291 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000292#ifdef DEBUG_EVAL_COUNTS
293 cur->nb = 0;
294#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000295 return(cur);
296}
297
298/**
299 * xmlXPathFreeCompExpr:
300 * @comp: an XPATH comp
301 *
302 * Free up the memory allocated by @comp
303 */
304void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000305xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
306{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000307 xmlXPathStepOpPtr op;
308 int i;
309
310 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000311 return;
312 for (i = 0; i < comp->nbStep; i++) {
313 op = &comp->steps[i];
314 if (op->value4 != NULL) {
315 if (op->op == XPATH_OP_VALUE)
316 xmlXPathFreeObject(op->value4);
317 else
318 xmlFree(op->value4);
319 }
320 if (op->value5 != NULL)
321 xmlFree(op->value5);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000322 }
323 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000324 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000325 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000326#ifdef DEBUG_EVAL_COUNTS
327 if (comp->string != NULL) {
328 xmlFree(comp->string);
329 }
330#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000331 if (comp->expr != NULL) {
332 xmlFree(comp->expr);
333 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000334
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000335 xmlFree(comp);
336}
337
338/**
339 * xmlXPathCompExprAdd:
340 * @comp: the compiled expression
341 * @ch1: first child index
342 * @ch2: second child index
343 * @op: an op
344 * @value: the first int value
345 * @value2: the second int value
346 * @value3: the third int value
347 * @value4: the first string value
348 * @value5: the second string value
349 *
350 * Add an step to an XPath Compiled Expression
351 *
352 * Returns -1 in case of failure, the index otherwise
353 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000354static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000355xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
356 xmlXPathOp op, int value,
357 int value2, int value3, void *value4, void *value5) {
358 if (comp->nbStep >= comp->maxStep) {
359 xmlXPathStepOp *real;
360
361 comp->maxStep *= 2;
362 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
363 comp->maxStep * sizeof(xmlXPathStepOp));
364 if (real == NULL) {
365 comp->maxStep /= 2;
366 xmlGenericError(xmlGenericErrorContext,
367 "xmlXPathCompExprAdd : realloc failed\n");
368 return(-1);
369 }
370 comp->steps = real;
371 }
372 comp->last = comp->nbStep;
373 comp->steps[comp->nbStep].ch1 = ch1;
374 comp->steps[comp->nbStep].ch2 = ch2;
375 comp->steps[comp->nbStep].op = op;
376 comp->steps[comp->nbStep].value = value;
377 comp->steps[comp->nbStep].value2 = value2;
378 comp->steps[comp->nbStep].value3 = value3;
379 comp->steps[comp->nbStep].value4 = value4;
380 comp->steps[comp->nbStep].value5 = value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000381 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000382 return(comp->nbStep++);
383}
384
Daniel Veillardf06307e2001-07-03 10:35:50 +0000385/**
386 * xmlXPathCompSwap:
387 * @comp: the compiled expression
388 * @op: operation index
389 *
390 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000391 */
392static void
393xmlXPathCompSwap(xmlXPathStepOpPtr op) {
394 int tmp;
395
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000396#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000397 /*
398 * Since this manipulates possibly shared variables, this is
399 * disable if one detects that the library is used in a multithreaded
400 * application
401 */
402 if (xmlXPathDisableOptimizer)
403 return;
404#endif
405
Daniel Veillardf06307e2001-07-03 10:35:50 +0000406 tmp = op->ch1;
407 op->ch1 = op->ch2;
408 op->ch2 = tmp;
409}
410
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000411#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
412 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
413 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000414#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
415 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
416 (op), (val), (val2), (val3), (val4), (val5))
417
418#define PUSH_LEAVE_EXPR(op, val, val2) \
419xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
420
421#define PUSH_UNARY_EXPR(op, ch, val, val2) \
422xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
423
424#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
425xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), (val), (val2), 0 ,NULL ,NULL)
426
427/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000428 * *
429 * Debugging related functions *
430 * *
431 ************************************************************************/
432
433#define TODO \
434 xmlGenericError(xmlGenericErrorContext, \
435 "Unimplemented block at %s:%d\n", \
436 __FILE__, __LINE__);
437
438#define STRANGE \
439 xmlGenericError(xmlGenericErrorContext, \
440 "Internal error at %s:%d\n", \
441 __FILE__, __LINE__);
442
443#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000444static void
445xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000446 int i;
447 char shift[100];
448
449 for (i = 0;((i < depth) && (i < 25));i++)
450 shift[2 * i] = shift[2 * i + 1] = ' ';
451 shift[2 * i] = shift[2 * i + 1] = 0;
452 if (cur == NULL) {
453 fprintf(output, shift);
454 fprintf(output, "Node is NULL !\n");
455 return;
456
457 }
458
459 if ((cur->type == XML_DOCUMENT_NODE) ||
460 (cur->type == XML_HTML_DOCUMENT_NODE)) {
461 fprintf(output, shift);
462 fprintf(output, " /\n");
463 } else if (cur->type == XML_ATTRIBUTE_NODE)
464 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
465 else
466 xmlDebugDumpOneNode(output, cur, depth);
467}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000468static void
469xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000470 xmlNodePtr tmp;
471 int i;
472 char shift[100];
473
474 for (i = 0;((i < depth) && (i < 25));i++)
475 shift[2 * i] = shift[2 * i + 1] = ' ';
476 shift[2 * i] = shift[2 * i + 1] = 0;
477 if (cur == NULL) {
478 fprintf(output, shift);
479 fprintf(output, "Node is NULL !\n");
480 return;
481
482 }
483
484 while (cur != NULL) {
485 tmp = cur;
486 cur = cur->next;
487 xmlDebugDumpOneNode(output, tmp, depth);
488 }
489}
Owen Taylor3473f882001-02-23 17:55:21 +0000490
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000491static void
492xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000493 int i;
494 char shift[100];
495
496 for (i = 0;((i < depth) && (i < 25));i++)
497 shift[2 * i] = shift[2 * i + 1] = ' ';
498 shift[2 * i] = shift[2 * i + 1] = 0;
499
500 if (cur == NULL) {
501 fprintf(output, shift);
502 fprintf(output, "NodeSet is NULL !\n");
503 return;
504
505 }
506
Daniel Veillard911f49a2001-04-07 15:39:35 +0000507 if (cur != NULL) {
508 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
509 for (i = 0;i < cur->nodeNr;i++) {
510 fprintf(output, shift);
511 fprintf(output, "%d", i + 1);
512 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
513 }
Owen Taylor3473f882001-02-23 17:55:21 +0000514 }
515}
516
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000517static void
518xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000519 int i;
520 char shift[100];
521
522 for (i = 0;((i < depth) && (i < 25));i++)
523 shift[2 * i] = shift[2 * i + 1] = ' ';
524 shift[2 * i] = shift[2 * i + 1] = 0;
525
526 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
527 fprintf(output, shift);
528 fprintf(output, "Value Tree is NULL !\n");
529 return;
530
531 }
532
533 fprintf(output, shift);
534 fprintf(output, "%d", i + 1);
535 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
536}
Owen Taylor3473f882001-02-23 17:55:21 +0000537#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000538static void
539xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000540 int i;
541 char shift[100];
542
543 for (i = 0;((i < depth) && (i < 25));i++)
544 shift[2 * i] = shift[2 * i + 1] = ' ';
545 shift[2 * i] = shift[2 * i + 1] = 0;
546
547 if (cur == NULL) {
548 fprintf(output, shift);
549 fprintf(output, "LocationSet is NULL !\n");
550 return;
551
552 }
553
554 for (i = 0;i < cur->locNr;i++) {
555 fprintf(output, shift);
556 fprintf(output, "%d : ", i + 1);
557 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
558 }
559}
Daniel Veillard017b1082001-06-21 11:20:21 +0000560#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000561
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000562/**
563 * xmlXPathDebugDumpObject:
564 * @output: the FILE * to dump the output
565 * @cur: the object to inspect
566 * @depth: indentation level
567 *
568 * Dump the content of the object for debugging purposes
569 */
570void
571xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000572 int i;
573 char shift[100];
574
575 for (i = 0;((i < depth) && (i < 25));i++)
576 shift[2 * i] = shift[2 * i + 1] = ' ';
577 shift[2 * i] = shift[2 * i + 1] = 0;
578
579 fprintf(output, shift);
580
581 if (cur == NULL) {
582 fprintf(output, "Object is empty (NULL)\n");
583 return;
584 }
585 switch(cur->type) {
586 case XPATH_UNDEFINED:
587 fprintf(output, "Object is uninitialized\n");
588 break;
589 case XPATH_NODESET:
590 fprintf(output, "Object is a Node Set :\n");
591 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
592 break;
593 case XPATH_XSLT_TREE:
594 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000595 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000596 break;
597 case XPATH_BOOLEAN:
598 fprintf(output, "Object is a Boolean : ");
599 if (cur->boolval) fprintf(output, "true\n");
600 else fprintf(output, "false\n");
601 break;
602 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +0000603 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000604 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000605 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000606 break;
607 case -1:
608 fprintf(output, "Object is a number : -Infinity\n");
609 break;
610 default:
Daniel Veillardcda96922001-08-21 10:56:31 +0000611 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000612 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +0000613 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
614 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000615 } else {
616 fprintf(output, "Object is a number : %0g\n", cur->floatval);
617 }
618 }
Owen Taylor3473f882001-02-23 17:55:21 +0000619 break;
620 case XPATH_STRING:
621 fprintf(output, "Object is a string : ");
622 xmlDebugDumpString(output, cur->stringval);
623 fprintf(output, "\n");
624 break;
625 case XPATH_POINT:
626 fprintf(output, "Object is a point : index %d in node", cur->index);
627 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
628 fprintf(output, "\n");
629 break;
630 case XPATH_RANGE:
631 if ((cur->user2 == NULL) ||
632 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
633 fprintf(output, "Object is a collapsed range :\n");
634 fprintf(output, shift);
635 if (cur->index >= 0)
636 fprintf(output, "index %d in ", cur->index);
637 fprintf(output, "node\n");
638 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
639 depth + 1);
640 } else {
641 fprintf(output, "Object is a range :\n");
642 fprintf(output, shift);
643 fprintf(output, "From ");
644 if (cur->index >= 0)
645 fprintf(output, "index %d in ", cur->index);
646 fprintf(output, "node\n");
647 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
648 depth + 1);
649 fprintf(output, shift);
650 fprintf(output, "To ");
651 if (cur->index2 >= 0)
652 fprintf(output, "index %d in ", cur->index2);
653 fprintf(output, "node\n");
654 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
655 depth + 1);
656 fprintf(output, "\n");
657 }
658 break;
659 case XPATH_LOCATIONSET:
660#if defined(LIBXML_XPTR_ENABLED)
661 fprintf(output, "Object is a Location Set:\n");
662 xmlXPathDebugDumpLocationSet(output,
663 (xmlLocationSetPtr) cur->user, depth);
664#endif
665 break;
666 case XPATH_USERS:
667 fprintf(output, "Object is user defined\n");
668 break;
669 }
670}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000671
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000672static void
673xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000674 xmlXPathStepOpPtr op, int depth) {
675 int i;
676 char shift[100];
677
678 for (i = 0;((i < depth) && (i < 25));i++)
679 shift[2 * i] = shift[2 * i + 1] = ' ';
680 shift[2 * i] = shift[2 * i + 1] = 0;
681
682 fprintf(output, shift);
683 if (op == NULL) {
684 fprintf(output, "Step is NULL\n");
685 return;
686 }
687 switch (op->op) {
688 case XPATH_OP_END:
689 fprintf(output, "END"); break;
690 case XPATH_OP_AND:
691 fprintf(output, "AND"); break;
692 case XPATH_OP_OR:
693 fprintf(output, "OR"); break;
694 case XPATH_OP_EQUAL:
695 if (op->value)
696 fprintf(output, "EQUAL =");
697 else
698 fprintf(output, "EQUAL !=");
699 break;
700 case XPATH_OP_CMP:
701 if (op->value)
702 fprintf(output, "CMP <");
703 else
704 fprintf(output, "CMP >");
705 if (!op->value2)
706 fprintf(output, "=");
707 break;
708 case XPATH_OP_PLUS:
709 if (op->value == 0)
710 fprintf(output, "PLUS -");
711 else if (op->value == 1)
712 fprintf(output, "PLUS +");
713 else if (op->value == 2)
714 fprintf(output, "PLUS unary -");
715 else if (op->value == 3)
716 fprintf(output, "PLUS unary - -");
717 break;
718 case XPATH_OP_MULT:
719 if (op->value == 0)
720 fprintf(output, "MULT *");
721 else if (op->value == 1)
722 fprintf(output, "MULT div");
723 else
724 fprintf(output, "MULT mod");
725 break;
726 case XPATH_OP_UNION:
727 fprintf(output, "UNION"); break;
728 case XPATH_OP_ROOT:
729 fprintf(output, "ROOT"); break;
730 case XPATH_OP_NODE:
731 fprintf(output, "NODE"); break;
732 case XPATH_OP_RESET:
733 fprintf(output, "RESET"); break;
734 case XPATH_OP_SORT:
735 fprintf(output, "SORT"); break;
736 case XPATH_OP_COLLECT: {
737 xmlXPathAxisVal axis = op->value;
738 xmlXPathTestVal test = op->value2;
739 xmlXPathTypeVal type = op->value3;
740 const xmlChar *prefix = op->value4;
741 const xmlChar *name = op->value5;
742
743 fprintf(output, "COLLECT ");
744 switch (axis) {
745 case AXIS_ANCESTOR:
746 fprintf(output, " 'ancestors' "); break;
747 case AXIS_ANCESTOR_OR_SELF:
748 fprintf(output, " 'ancestors-or-self' "); break;
749 case AXIS_ATTRIBUTE:
750 fprintf(output, " 'attributes' "); break;
751 case AXIS_CHILD:
752 fprintf(output, " 'child' "); break;
753 case AXIS_DESCENDANT:
754 fprintf(output, " 'descendant' "); break;
755 case AXIS_DESCENDANT_OR_SELF:
756 fprintf(output, " 'descendant-or-self' "); break;
757 case AXIS_FOLLOWING:
758 fprintf(output, " 'following' "); break;
759 case AXIS_FOLLOWING_SIBLING:
760 fprintf(output, " 'following-siblings' "); break;
761 case AXIS_NAMESPACE:
762 fprintf(output, " 'namespace' "); break;
763 case AXIS_PARENT:
764 fprintf(output, " 'parent' "); break;
765 case AXIS_PRECEDING:
766 fprintf(output, " 'preceding' "); break;
767 case AXIS_PRECEDING_SIBLING:
768 fprintf(output, " 'preceding-sibling' "); break;
769 case AXIS_SELF:
770 fprintf(output, " 'self' "); break;
771 }
772 switch (test) {
773 case NODE_TEST_NONE:
774 fprintf(output, "'none' "); break;
775 case NODE_TEST_TYPE:
776 fprintf(output, "'type' "); break;
777 case NODE_TEST_PI:
778 fprintf(output, "'PI' "); break;
779 case NODE_TEST_ALL:
780 fprintf(output, "'all' "); break;
781 case NODE_TEST_NS:
782 fprintf(output, "'namespace' "); break;
783 case NODE_TEST_NAME:
784 fprintf(output, "'name' "); break;
785 }
786 switch (type) {
787 case NODE_TYPE_NODE:
788 fprintf(output, "'node' "); break;
789 case NODE_TYPE_COMMENT:
790 fprintf(output, "'comment' "); break;
791 case NODE_TYPE_TEXT:
792 fprintf(output, "'text' "); break;
793 case NODE_TYPE_PI:
794 fprintf(output, "'PI' "); break;
795 }
796 if (prefix != NULL)
797 fprintf(output, "%s:", prefix);
798 if (name != NULL)
799 fprintf(output, "%s", name);
800 break;
801
802 }
803 case XPATH_OP_VALUE: {
804 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
805
806 fprintf(output, "ELEM ");
807 xmlXPathDebugDumpObject(output, object, 0);
808 goto finish;
809 }
810 case XPATH_OP_VARIABLE: {
811 const xmlChar *prefix = op->value5;
812 const xmlChar *name = op->value4;
813
814 if (prefix != NULL)
815 fprintf(output, "VARIABLE %s:%s", prefix, name);
816 else
817 fprintf(output, "VARIABLE %s", name);
818 break;
819 }
820 case XPATH_OP_FUNCTION: {
821 int nbargs = op->value;
822 const xmlChar *prefix = op->value5;
823 const xmlChar *name = op->value4;
824
825 if (prefix != NULL)
826 fprintf(output, "FUNCTION %s:%s(%d args)",
827 prefix, name, nbargs);
828 else
829 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
830 break;
831 }
832 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
833 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000834 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +0000835#ifdef LIBXML_XPTR_ENABLED
836 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
837#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000838 default:
839 fprintf(output, "UNKNOWN %d\n", op->op); return;
840 }
841 fprintf(output, "\n");
842finish:
843 if (op->ch1 >= 0)
844 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
845 if (op->ch2 >= 0)
846 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
847}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000848
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000849/**
850 * xmlXPathDebugDumpCompExpr:
851 * @output: the FILE * for the output
852 * @comp: the precompiled XPath expression
853 * @depth: the indentation level.
854 *
855 * Dumps the tree of the compiled XPath expression.
856 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000857void
858xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
859 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000860 int i;
861 char shift[100];
862
863 for (i = 0;((i < depth) && (i < 25));i++)
864 shift[2 * i] = shift[2 * i + 1] = ' ';
865 shift[2 * i] = shift[2 * i + 1] = 0;
866
867 fprintf(output, shift);
868
869 if (comp == NULL) {
870 fprintf(output, "Compiled Expression is NULL\n");
871 return;
872 }
873 fprintf(output, "Compiled Expression : %d elements\n",
874 comp->nbStep);
875 i = comp->last;
876 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
877}
Daniel Veillard017b1082001-06-21 11:20:21 +0000878#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000879
880/************************************************************************
881 * *
882 * Parser stacks related functions and macros *
883 * *
884 ************************************************************************/
885
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000886/**
887 * valuePop:
888 * @ctxt: an XPath evaluation context
889 *
890 * Pops the top XPath object from the value stack
891 *
892 * Returns the XPath object just removed
893 */
Daniel Veillard1c732d22002-11-30 11:22:59 +0000894extern xmlXPathObjectPtr
895valuePop(xmlXPathParserContextPtr ctxt)
896{
897 xmlXPathObjectPtr ret;
898
899 if (ctxt->valueNr <= 0)
900 return (0);
901 ctxt->valueNr--;
902 if (ctxt->valueNr > 0)
903 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
904 else
905 ctxt->value = NULL;
906 ret = ctxt->valueTab[ctxt->valueNr];
907 ctxt->valueTab[ctxt->valueNr] = 0;
908 return (ret);
909}
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000910/**
911 * valuePush:
912 * @ctxt: an XPath evaluation context
913 * @value: the XPath object
914 *
915 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000916 *
917 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000918 */
Daniel Veillard1c732d22002-11-30 11:22:59 +0000919extern int
920valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
921{
922 if (ctxt->valueNr >= ctxt->valueMax) {
923 ctxt->valueMax *= 2;
924 ctxt->valueTab =
925 (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
926 ctxt->valueMax *
927 sizeof(ctxt->valueTab[0]));
928 if (ctxt->valueTab == NULL) {
929 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
930 return (0);
931 }
932 }
933 ctxt->valueTab[ctxt->valueNr] = value;
934 ctxt->value = value;
935 return (ctxt->valueNr++);
936}
Owen Taylor3473f882001-02-23 17:55:21 +0000937
Thomas Broyerf06a3d82001-07-16 04:52:57 +0000938/**
939 * xmlXPathPopBoolean:
940 * @ctxt: an XPath parser context
941 *
942 * Pops a boolean from the stack, handling conversion if needed.
943 * Check error with #xmlXPathCheckError.
944 *
945 * Returns the boolean
946 */
947int
948xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
949 xmlXPathObjectPtr obj;
950 int ret;
951
952 obj = valuePop(ctxt);
953 if (obj == NULL) {
954 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
955 return(0);
956 }
957 ret = xmlXPathCastToBoolean(obj);
958 xmlXPathFreeObject(obj);
959 return(ret);
960}
961
962/**
963 * xmlXPathPopNumber:
964 * @ctxt: an XPath parser context
965 *
966 * Pops a number from the stack, handling conversion if needed.
967 * Check error with #xmlXPathCheckError.
968 *
969 * Returns the number
970 */
971double
972xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
973 xmlXPathObjectPtr obj;
974 double ret;
975
976 obj = valuePop(ctxt);
977 if (obj == NULL) {
978 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
979 return(0);
980 }
981 ret = xmlXPathCastToNumber(obj);
982 xmlXPathFreeObject(obj);
983 return(ret);
984}
985
986/**
987 * xmlXPathPopString:
988 * @ctxt: an XPath parser context
989 *
990 * Pops a string from the stack, handling conversion if needed.
991 * Check error with #xmlXPathCheckError.
992 *
993 * Returns the string
994 */
995xmlChar *
996xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
997 xmlXPathObjectPtr obj;
998 xmlChar * ret;
999
1000 obj = valuePop(ctxt);
1001 if (obj == NULL) {
1002 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1003 return(NULL);
1004 }
1005 ret = xmlXPathCastToString(obj);
1006 /* TODO: needs refactoring somewhere else */
1007 if (obj->stringval == ret)
1008 obj->stringval = NULL;
1009 xmlXPathFreeObject(obj);
1010 return(ret);
1011}
1012
1013/**
1014 * xmlXPathPopNodeSet:
1015 * @ctxt: an XPath parser context
1016 *
1017 * Pops a node-set from the stack, handling conversion if needed.
1018 * Check error with #xmlXPathCheckError.
1019 *
1020 * Returns the node-set
1021 */
1022xmlNodeSetPtr
1023xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
1024 xmlXPathObjectPtr obj;
1025 xmlNodeSetPtr ret;
1026
1027 if (ctxt->value == NULL) {
1028 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1029 return(NULL);
1030 }
1031 if (!xmlXPathStackIsNodeSet(ctxt)) {
1032 xmlXPathSetTypeError(ctxt);
1033 return(NULL);
1034 }
1035 obj = valuePop(ctxt);
1036 ret = obj->nodesetval;
1037 xmlXPathFreeNodeSetList(obj);
1038 return(ret);
1039}
1040
1041/**
1042 * xmlXPathPopExternal:
1043 * @ctxt: an XPath parser context
1044 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001045 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001046 * Check error with #xmlXPathCheckError.
1047 *
1048 * Returns the object
1049 */
1050void *
1051xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1052 xmlXPathObjectPtr obj;
1053 void * ret;
1054
1055 if (ctxt->value == NULL) {
1056 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1057 return(NULL);
1058 }
1059 if (ctxt->value->type != XPATH_USERS) {
1060 xmlXPathSetTypeError(ctxt);
1061 return(NULL);
1062 }
1063 obj = valuePop(ctxt);
1064 ret = obj->user;
1065 xmlXPathFreeObject(obj);
1066 return(ret);
1067}
1068
Owen Taylor3473f882001-02-23 17:55:21 +00001069/*
1070 * Macros for accessing the content. Those should be used only by the parser,
1071 * and not exported.
1072 *
1073 * Dirty macros, i.e. one need to make assumption on the context to use them
1074 *
1075 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1076 * CUR returns the current xmlChar value, i.e. a 8 bit value
1077 * in ISO-Latin or UTF-8.
1078 * This should be used internally by the parser
1079 * only to compare to ASCII values otherwise it would break when
1080 * running with UTF-8 encoding.
1081 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1082 * to compare on ASCII based substring.
1083 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1084 * strings within the parser.
1085 * CURRENT Returns the current char value, with the full decoding of
1086 * UTF-8 if we are using this mode. It returns an int.
1087 * NEXT Skip to the next character, this does the proper decoding
1088 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1089 * It returns the pointer to the current xmlChar.
1090 */
1091
1092#define CUR (*ctxt->cur)
1093#define SKIP(val) ctxt->cur += (val)
1094#define NXT(val) ctxt->cur[(val)]
1095#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001096#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1097
1098#define COPY_BUF(l,b,i,v) \
1099 if (l == 1) b[i++] = (xmlChar) v; \
1100 else i += xmlCopyChar(l,&b[i],v)
1101
1102#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001103
1104#define SKIP_BLANKS \
1105 while (IS_BLANK(*(ctxt->cur))) NEXT
1106
1107#define CURRENT (*ctxt->cur)
1108#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1109
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001110
1111#ifndef DBL_DIG
1112#define DBL_DIG 16
1113#endif
1114#ifndef DBL_EPSILON
1115#define DBL_EPSILON 1E-9
1116#endif
1117
1118#define UPPER_DOUBLE 1E9
1119#define LOWER_DOUBLE 1E-5
1120
1121#define INTEGER_DIGITS DBL_DIG
1122#define FRACTION_DIGITS (DBL_DIG + 1)
1123#define EXPONENT_DIGITS (3 + 2)
1124
1125/**
1126 * xmlXPathFormatNumber:
1127 * @number: number to format
1128 * @buffer: output buffer
1129 * @buffersize: size of output buffer
1130 *
1131 * Convert the number into a string representation.
1132 */
1133static void
1134xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1135{
Daniel Veillardcda96922001-08-21 10:56:31 +00001136 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001137 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001138 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001139 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001140 break;
1141 case -1:
1142 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 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001146 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001147 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001148 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001149 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001150 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001151 } else if (number == ((int) number)) {
1152 char work[30];
1153 char *ptr, *cur;
1154 int res, value = (int) number;
1155
1156 ptr = &buffer[0];
1157 if (value < 0) {
1158 *ptr++ = '-';
1159 value = -value;
1160 }
1161 if (value == 0) {
1162 *ptr++ = '0';
1163 } else {
1164 cur = &work[0];
1165 while (value != 0) {
1166 res = value % 10;
1167 value = value / 10;
1168 *cur++ = '0' + res;
1169 }
1170 cur--;
1171 while ((cur >= &work[0]) && (ptr - buffer < buffersize)) {
1172 *ptr++ = *cur--;
1173 }
1174 }
1175 if (ptr - buffer < buffersize) {
1176 *ptr = 0;
1177 } else if (buffersize > 0) {
1178 ptr--;
1179 *ptr = 0;
1180 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001181 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001182 /* 3 is sign, decimal point, and terminating zero */
1183 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1184 int integer_place, fraction_place;
1185 char *ptr;
1186 char *after_fraction;
1187 double absolute_value;
1188 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001189
Bjorn Reese70a9da52001-04-21 16:57:29 +00001190 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001191
Bjorn Reese70a9da52001-04-21 16:57:29 +00001192 /*
1193 * First choose format - scientific or regular floating point.
1194 * In either case, result is in work, and after_fraction points
1195 * just past the fractional part.
1196 */
1197 if ( ((absolute_value > UPPER_DOUBLE) ||
1198 (absolute_value < LOWER_DOUBLE)) &&
1199 (absolute_value != 0.0) ) {
1200 /* Use scientific notation */
1201 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1202 fraction_place = DBL_DIG - 1;
1203 snprintf(work, sizeof(work),"%*.*e",
1204 integer_place, fraction_place, number);
1205 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001206 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001207 else {
1208 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001209 if (absolute_value > 0.0)
1210 integer_place = 1 + (int)log10(absolute_value);
1211 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001212 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001213 fraction_place = (integer_place > 0)
1214 ? DBL_DIG - integer_place
1215 : DBL_DIG;
1216 size = snprintf(work, sizeof(work), "%0.*f",
1217 fraction_place, number);
1218 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001219 }
1220
Bjorn Reese70a9da52001-04-21 16:57:29 +00001221 /* Remove fractional trailing zeroes */
1222 ptr = after_fraction;
1223 while (*(--ptr) == '0')
1224 ;
1225 if (*ptr != '.')
1226 ptr++;
1227 strcpy(ptr, after_fraction);
1228
1229 /* Finally copy result back to caller */
1230 size = strlen(work) + 1;
1231 if (size > buffersize) {
1232 work[buffersize - 1] = 0;
1233 size = buffersize;
1234 }
1235 memcpy(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001236 }
1237 break;
1238 }
1239}
1240
Owen Taylor3473f882001-02-23 17:55:21 +00001241/************************************************************************
1242 * *
1243 * Error handling routines *
1244 * *
1245 ************************************************************************/
1246
1247
Daniel Veillardb44025c2001-10-11 22:55:55 +00001248static const char *xmlXPathErrorMessages[] = {
Owen Taylor3473f882001-02-23 17:55:21 +00001249 "Ok",
1250 "Number encoding",
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001251 "Unfinished literal",
1252 "Start of literal",
Owen Taylor3473f882001-02-23 17:55:21 +00001253 "Expected $ for variable reference",
1254 "Undefined variable",
1255 "Invalid predicate",
1256 "Invalid expression",
1257 "Missing closing curly brace",
1258 "Unregistered function",
1259 "Invalid operand",
1260 "Invalid type",
1261 "Invalid number of arguments",
1262 "Invalid context size",
1263 "Invalid context position",
1264 "Memory allocation error",
1265 "Syntax error",
1266 "Resource error",
1267 "Sub resource error",
Daniel Veillard61d80a22001-04-27 17:13:01 +00001268 "Undefined namespace prefix",
1269 "Encoding error",
1270 "Char out of XML range"
Owen Taylor3473f882001-02-23 17:55:21 +00001271};
1272
1273/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001274 * xmlXPatherror:
Owen Taylor3473f882001-02-23 17:55:21 +00001275 * @ctxt: the XPath Parser context
1276 * @file: the file name
1277 * @line: the line number
1278 * @no: the error number
1279 *
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001280 * Formats an error message.
Owen Taylor3473f882001-02-23 17:55:21 +00001281 */
1282void
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00001283xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
1284 int line ATTRIBUTE_UNUSED, int no) {
Owen Taylor3473f882001-02-23 17:55:21 +00001285 int n;
1286 const xmlChar *cur;
1287 const xmlChar *base;
1288
Owen Taylor3473f882001-02-23 17:55:21 +00001289 cur = ctxt->cur;
1290 base = ctxt->base;
Daniel Veillard118aed72002-09-24 14:13:13 +00001291 if ((cur == NULL) || (base == NULL)) {
1292 if ((ctxt->comp != NULL) && (ctxt->comp->expr != NULL)) {
1293 xmlGenericError(xmlGenericErrorContext,
1294 "XPath error %s in %s\n", xmlXPathErrorMessages[no],
1295 ctxt->comp->expr);
1296 } else {
1297 xmlGenericError(xmlGenericErrorContext,
1298 "XPath error %s\n", xmlXPathErrorMessages[no]);
1299 }
1300
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001301 return;
Daniel Veillard118aed72002-09-24 14:13:13 +00001302 }
1303 xmlGenericError(xmlGenericErrorContext,
1304 "XPath error %s\n", xmlXPathErrorMessages[no]);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001305
Owen Taylor3473f882001-02-23 17:55:21 +00001306 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
1307 cur--;
1308 }
1309 n = 0;
1310 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
1311 cur--;
1312 if ((*cur == '\n') || (*cur == '\r')) cur++;
1313 base = cur;
1314 n = 0;
1315 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
1316 xmlGenericError(xmlGenericErrorContext, "%c", (unsigned char) *cur++);
1317 n++;
1318 }
1319 xmlGenericError(xmlGenericErrorContext, "\n");
1320 cur = ctxt->cur;
1321 while ((*cur == '\n') || (*cur == '\r'))
1322 cur--;
1323 n = 0;
1324 while ((cur != base) && (n++ < 80)) {
1325 xmlGenericError(xmlGenericErrorContext, " ");
1326 base++;
1327 }
1328 xmlGenericError(xmlGenericErrorContext,"^\n");
1329}
1330
1331
1332/************************************************************************
1333 * *
1334 * Routines to handle NodeSets *
1335 * *
1336 ************************************************************************/
1337
1338/**
1339 * xmlXPathCmpNodes:
1340 * @node1: the first node
1341 * @node2: the second node
1342 *
1343 * Compare two nodes w.r.t document order
1344 *
1345 * Returns -2 in case of error 1 if first point < second point, 0 if
1346 * that's the same node, -1 otherwise
1347 */
1348int
1349xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1350 int depth1, depth2;
1351 xmlNodePtr cur, root;
1352
1353 if ((node1 == NULL) || (node2 == NULL))
1354 return(-2);
1355 /*
1356 * a couple of optimizations which will avoid computations in most cases
1357 */
1358 if (node1 == node2)
1359 return(0);
Daniel Veillardb33c2012001-04-25 12:59:04 +00001360 if ((node1->type == XML_NAMESPACE_DECL) ||
1361 (node2->type == XML_NAMESPACE_DECL))
1362 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001363 if (node1 == node2->prev)
1364 return(1);
1365 if (node1 == node2->next)
1366 return(-1);
1367
Daniel Veillard68e9e742002-11-16 15:35:11 +00001368#if 0
1369 Unfortunately this does not work. Line number in entities reset
1370 to 1 within the entity :-(
1371
Owen Taylor3473f882001-02-23 17:55:21 +00001372 /*
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001373 * Speedup using line numbers if availble.
1374 */
1375 if ((node1->type == XML_ELEMENT_NODE) &&
1376 (node2->type == XML_ELEMENT_NODE) &&
1377 (0 != (int) node1->content) && (0 != (int) node2->content)) {
1378 int l1, l2;
1379 l1 = (int) node1->content;
1380 l2 = (int) node2->content;
1381 if (l1 < l2)
1382 return(1);
1383 if (l1 > l2)
1384 return(-1);
1385 }
Daniel Veillard68e9e742002-11-16 15:35:11 +00001386#endif
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001387 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001388 * compute depth to root
1389 */
1390 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1391 if (cur == node1)
1392 return(1);
1393 depth2++;
1394 }
1395 root = cur;
1396 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1397 if (cur == node2)
1398 return(-1);
1399 depth1++;
1400 }
1401 /*
1402 * Distinct document (or distinct entities :-( ) case.
1403 */
1404 if (root != cur) {
1405 return(-2);
1406 }
1407 /*
1408 * get the nearest common ancestor.
1409 */
1410 while (depth1 > depth2) {
1411 depth1--;
1412 node1 = node1->parent;
1413 }
1414 while (depth2 > depth1) {
1415 depth2--;
1416 node2 = node2->parent;
1417 }
1418 while (node1->parent != node2->parent) {
1419 node1 = node1->parent;
1420 node2 = node2->parent;
1421 /* should not happen but just in case ... */
1422 if ((node1 == NULL) || (node2 == NULL))
1423 return(-2);
1424 }
1425 /*
1426 * Find who's first.
1427 */
1428 if (node1 == node2->next)
1429 return(-1);
1430 for (cur = node1->next;cur != NULL;cur = cur->next)
1431 if (cur == node2)
1432 return(1);
1433 return(-1); /* assume there is no sibling list corruption */
1434}
1435
1436/**
1437 * xmlXPathNodeSetSort:
1438 * @set: the node set
1439 *
1440 * Sort the node set in document order
1441 */
1442void
1443xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001444 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001445 xmlNodePtr tmp;
1446
1447 if (set == NULL)
1448 return;
1449
1450 /* Use Shell's sort to sort the node-set */
1451 len = set->nodeNr;
1452 for (incr = len / 2; incr > 0; incr /= 2) {
1453 for (i = incr; i < len; i++) {
1454 j = i - incr;
1455 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001456 if (xmlXPathCmpNodes(set->nodeTab[j],
1457 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001458 tmp = set->nodeTab[j];
1459 set->nodeTab[j] = set->nodeTab[j + incr];
1460 set->nodeTab[j + incr] = tmp;
1461 j -= incr;
1462 } else
1463 break;
1464 }
1465 }
1466 }
1467}
1468
1469#define XML_NODESET_DEFAULT 10
1470/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001471 * xmlXPathNodeSetDupNs:
1472 * @node: the parent node of the namespace XPath node
1473 * @ns: the libxml namespace declaration node.
1474 *
1475 * Namespace node in libxml don't match the XPath semantic. In a node set
1476 * the namespace nodes are duplicated and the next pointer is set to the
1477 * parent node in the XPath semantic.
1478 *
1479 * Returns the newly created object.
1480 */
1481static xmlNodePtr
1482xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
1483 xmlNsPtr cur;
1484
1485 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1486 return(NULL);
1487 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
1488 return((xmlNodePtr) ns);
1489
1490 /*
1491 * Allocate a new Namespace and fill the fields.
1492 */
1493 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1494 if (cur == NULL) {
1495 xmlGenericError(xmlGenericErrorContext,
1496 "xmlXPathNodeSetDupNs : malloc failed\n");
1497 return(NULL);
1498 }
1499 memset(cur, 0, sizeof(xmlNs));
1500 cur->type = XML_NAMESPACE_DECL;
1501 if (ns->href != NULL)
1502 cur->href = xmlStrdup(ns->href);
1503 if (ns->prefix != NULL)
1504 cur->prefix = xmlStrdup(ns->prefix);
1505 cur->next = (xmlNsPtr) node;
1506 return((xmlNodePtr) cur);
1507}
1508
1509/**
1510 * xmlXPathNodeSetFreeNs:
1511 * @ns: the XPath namespace node found in a nodeset.
1512 *
1513 * Namespace node in libxml don't match the XPath semantic. In a node set
1514 * the namespace nodes are duplicated and the next pointer is set to the
1515 * parent node in the XPath semantic. Check if such a node need to be freed
1516 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001517void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001518xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
1519 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1520 return;
1521
1522 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
1523 if (ns->href != NULL)
1524 xmlFree((xmlChar *)ns->href);
1525 if (ns->prefix != NULL)
1526 xmlFree((xmlChar *)ns->prefix);
1527 xmlFree(ns);
1528 }
1529}
1530
1531/**
Owen Taylor3473f882001-02-23 17:55:21 +00001532 * xmlXPathNodeSetCreate:
1533 * @val: an initial xmlNodePtr, or NULL
1534 *
1535 * Create a new xmlNodeSetPtr of type double and of value @val
1536 *
1537 * Returns the newly created object.
1538 */
1539xmlNodeSetPtr
1540xmlXPathNodeSetCreate(xmlNodePtr val) {
1541 xmlNodeSetPtr ret;
1542
1543 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1544 if (ret == NULL) {
1545 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001546 "xmlXPathNodeSetCreate: out of memory\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001547 return(NULL);
1548 }
1549 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1550 if (val != NULL) {
1551 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1552 sizeof(xmlNodePtr));
1553 if (ret->nodeTab == NULL) {
1554 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001555 "xmlXPathNodeSetCreate: out of memory\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001556 return(NULL);
1557 }
1558 memset(ret->nodeTab, 0 ,
1559 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1560 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001561 if (val->type == XML_NAMESPACE_DECL) {
1562 xmlNsPtr ns = (xmlNsPtr) val;
1563
1564 ret->nodeTab[ret->nodeNr++] =
1565 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1566 } else
1567 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001568 }
1569 return(ret);
1570}
1571
1572/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001573 * xmlXPathNodeSetContains:
1574 * @cur: the node-set
1575 * @val: the node
1576 *
1577 * checks whether @cur contains @val
1578 *
1579 * Returns true (1) if @cur contains @val, false (0) otherwise
1580 */
1581int
1582xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1583 int i;
1584
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001585 if (val->type == XML_NAMESPACE_DECL) {
1586 for (i = 0; i < cur->nodeNr; i++) {
1587 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1588 xmlNsPtr ns1, ns2;
1589
1590 ns1 = (xmlNsPtr) val;
1591 ns2 = (xmlNsPtr) cur->nodeTab[i];
1592 if (ns1 == ns2)
1593 return(1);
1594 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
1595 (xmlStrEqual(ns1->prefix, ns2->prefix)))
1596 return(1);
1597 }
1598 }
1599 } else {
1600 for (i = 0; i < cur->nodeNr; i++) {
1601 if (cur->nodeTab[i] == val)
1602 return(1);
1603 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001604 }
1605 return(0);
1606}
1607
1608/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001609 * xmlXPathNodeSetAddNs:
1610 * @cur: the initial node set
1611 * @node: the hosting node
1612 * @ns: a the namespace node
1613 *
1614 * add a new namespace node to an existing NodeSet
1615 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00001616void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001617xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
1618 int i;
1619
1620 if ((ns == NULL) || (node == NULL) || (ns->type != XML_NAMESPACE_DECL) ||
1621 (node->type != XML_ELEMENT_NODE))
1622 return;
1623
1624 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1625 /*
1626 * check against doublons
1627 */
1628 for (i = 0;i < cur->nodeNr;i++) {
1629 if ((cur->nodeTab[i] != NULL) &&
1630 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00001631 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001632 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
1633 return;
1634 }
1635
1636 /*
1637 * grow the nodeTab if needed
1638 */
1639 if (cur->nodeMax == 0) {
1640 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1641 sizeof(xmlNodePtr));
1642 if (cur->nodeTab == NULL) {
1643 xmlGenericError(xmlGenericErrorContext,
1644 "xmlXPathNodeSetAdd: out of memory\n");
1645 return;
1646 }
1647 memset(cur->nodeTab, 0 ,
1648 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1649 cur->nodeMax = XML_NODESET_DEFAULT;
1650 } else if (cur->nodeNr == cur->nodeMax) {
1651 xmlNodePtr *temp;
1652
1653 cur->nodeMax *= 2;
1654 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1655 sizeof(xmlNodePtr));
1656 if (temp == NULL) {
1657 xmlGenericError(xmlGenericErrorContext,
1658 "xmlXPathNodeSetAdd: out of memory\n");
1659 return;
1660 }
1661 cur->nodeTab = temp;
1662 }
1663 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
1664}
1665
1666/**
Owen Taylor3473f882001-02-23 17:55:21 +00001667 * xmlXPathNodeSetAdd:
1668 * @cur: the initial node set
1669 * @val: a new xmlNodePtr
1670 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001671 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00001672 */
1673void
1674xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1675 int i;
1676
1677 if (val == NULL) return;
1678
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001679 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001680 /*
1681 * check against doublons
1682 */
1683 for (i = 0;i < cur->nodeNr;i++)
1684 if (cur->nodeTab[i] == val) return;
1685
1686 /*
1687 * grow the nodeTab if needed
1688 */
1689 if (cur->nodeMax == 0) {
1690 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1691 sizeof(xmlNodePtr));
1692 if (cur->nodeTab == NULL) {
1693 xmlGenericError(xmlGenericErrorContext,
1694 "xmlXPathNodeSetAdd: out of memory\n");
1695 return;
1696 }
1697 memset(cur->nodeTab, 0 ,
1698 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1699 cur->nodeMax = XML_NODESET_DEFAULT;
1700 } else if (cur->nodeNr == cur->nodeMax) {
1701 xmlNodePtr *temp;
1702
1703 cur->nodeMax *= 2;
1704 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1705 sizeof(xmlNodePtr));
1706 if (temp == NULL) {
1707 xmlGenericError(xmlGenericErrorContext,
1708 "xmlXPathNodeSetAdd: out of memory\n");
1709 return;
1710 }
1711 cur->nodeTab = temp;
1712 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001713 if (val->type == XML_NAMESPACE_DECL) {
1714 xmlNsPtr ns = (xmlNsPtr) val;
1715
1716 cur->nodeTab[cur->nodeNr++] =
1717 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1718 } else
1719 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001720}
1721
1722/**
1723 * xmlXPathNodeSetAddUnique:
1724 * @cur: the initial node set
1725 * @val: a new xmlNodePtr
1726 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001727 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00001728 * when we are sure the node is not already in the set.
1729 */
1730void
1731xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1732 if (val == NULL) return;
1733
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001734 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001735 /*
1736 * grow the nodeTab if needed
1737 */
1738 if (cur->nodeMax == 0) {
1739 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1740 sizeof(xmlNodePtr));
1741 if (cur->nodeTab == NULL) {
1742 xmlGenericError(xmlGenericErrorContext,
1743 "xmlXPathNodeSetAddUnique: out of memory\n");
1744 return;
1745 }
1746 memset(cur->nodeTab, 0 ,
1747 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1748 cur->nodeMax = XML_NODESET_DEFAULT;
1749 } else if (cur->nodeNr == cur->nodeMax) {
1750 xmlNodePtr *temp;
1751
1752 cur->nodeMax *= 2;
1753 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1754 sizeof(xmlNodePtr));
1755 if (temp == NULL) {
1756 xmlGenericError(xmlGenericErrorContext,
1757 "xmlXPathNodeSetAddUnique: out of memory\n");
1758 return;
1759 }
1760 cur->nodeTab = temp;
1761 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001762 if (val->type == XML_NAMESPACE_DECL) {
1763 xmlNsPtr ns = (xmlNsPtr) val;
1764
1765 cur->nodeTab[cur->nodeNr++] =
1766 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1767 } else
1768 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001769}
1770
1771/**
1772 * xmlXPathNodeSetMerge:
1773 * @val1: the first NodeSet or NULL
1774 * @val2: the second NodeSet
1775 *
1776 * Merges two nodesets, all nodes from @val2 are added to @val1
1777 * if @val1 is NULL, a new set is created and copied from @val2
1778 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001779 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00001780 */
1781xmlNodeSetPtr
1782xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001783 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001784
1785 if (val2 == NULL) return(val1);
1786 if (val1 == NULL) {
1787 val1 = xmlXPathNodeSetCreate(NULL);
1788 }
1789
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001790 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001791 initNr = val1->nodeNr;
1792
1793 for (i = 0;i < val2->nodeNr;i++) {
1794 /*
1795 * check against doublons
1796 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001797 skip = 0;
1798 for (j = 0; j < initNr; j++) {
1799 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1800 skip = 1;
1801 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001802 } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) &&
1803 (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) {
1804 xmlNsPtr ns1, ns2;
1805 ns1 = (xmlNsPtr) val1->nodeTab[j];
1806 ns2 = (xmlNsPtr) val2->nodeTab[i];
1807 if ((ns1->next == ns2->next) &&
1808 (xmlStrEqual(ns1->prefix, ns2->prefix))) {
1809 skip = 1;
1810 break;
1811 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001812 }
1813 }
1814 if (skip)
1815 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00001816
1817 /*
1818 * grow the nodeTab if needed
1819 */
1820 if (val1->nodeMax == 0) {
1821 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1822 sizeof(xmlNodePtr));
1823 if (val1->nodeTab == NULL) {
1824 xmlGenericError(xmlGenericErrorContext,
1825 "xmlXPathNodeSetMerge: out of memory\n");
1826 return(NULL);
1827 }
1828 memset(val1->nodeTab, 0 ,
1829 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1830 val1->nodeMax = XML_NODESET_DEFAULT;
1831 } else if (val1->nodeNr == val1->nodeMax) {
1832 xmlNodePtr *temp;
1833
1834 val1->nodeMax *= 2;
1835 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1836 sizeof(xmlNodePtr));
1837 if (temp == NULL) {
1838 xmlGenericError(xmlGenericErrorContext,
1839 "xmlXPathNodeSetMerge: out of memory\n");
1840 return(NULL);
1841 }
1842 val1->nodeTab = temp;
1843 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001844 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1845 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1846
1847 val1->nodeTab[val1->nodeNr++] =
1848 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1849 } else
1850 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00001851 }
1852
1853 return(val1);
1854}
1855
1856/**
Daniel Veillard75be0132002-03-13 10:03:35 +00001857 * xmlXPathNodeSetMergeUnique:
1858 * @val1: the first NodeSet or NULL
1859 * @val2: the second NodeSet
1860 *
1861 * Merges two nodesets, all nodes from @val2 are added to @val1
1862 * if @val1 is NULL, a new set is created and copied from @val2
1863 *
1864 * Returns @val1 once extended or NULL in case of error.
1865 */
1866static xmlNodeSetPtr
1867xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
1868 int i, initNr;
1869
1870 if (val2 == NULL) return(val1);
1871 if (val1 == NULL) {
1872 val1 = xmlXPathNodeSetCreate(NULL);
1873 }
1874
1875 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1876 initNr = val1->nodeNr;
1877
1878 for (i = 0;i < val2->nodeNr;i++) {
1879 /*
1880 * grow the nodeTab if needed
1881 */
1882 if (val1->nodeMax == 0) {
1883 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1884 sizeof(xmlNodePtr));
1885 if (val1->nodeTab == NULL) {
1886 xmlGenericError(xmlGenericErrorContext,
1887 "xmlXPathNodeSetMerge: out of memory\n");
1888 return(NULL);
1889 }
1890 memset(val1->nodeTab, 0 ,
1891 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1892 val1->nodeMax = XML_NODESET_DEFAULT;
1893 } else if (val1->nodeNr == val1->nodeMax) {
1894 xmlNodePtr *temp;
1895
1896 val1->nodeMax *= 2;
1897 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1898 sizeof(xmlNodePtr));
1899 if (temp == NULL) {
1900 xmlGenericError(xmlGenericErrorContext,
1901 "xmlXPathNodeSetMerge: out of memory\n");
1902 return(NULL);
1903 }
1904 val1->nodeTab = temp;
1905 }
1906 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1907 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1908
1909 val1->nodeTab[val1->nodeNr++] =
1910 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1911 } else
1912 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
1913 }
1914
1915 return(val1);
1916}
1917
1918/**
Owen Taylor3473f882001-02-23 17:55:21 +00001919 * xmlXPathNodeSetDel:
1920 * @cur: the initial node set
1921 * @val: an xmlNodePtr
1922 *
1923 * Removes an xmlNodePtr from an existing NodeSet
1924 */
1925void
1926xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
1927 int i;
1928
1929 if (cur == NULL) return;
1930 if (val == NULL) return;
1931
1932 /*
1933 * check against doublons
1934 */
1935 for (i = 0;i < cur->nodeNr;i++)
1936 if (cur->nodeTab[i] == val) break;
1937
1938 if (i >= cur->nodeNr) {
1939#ifdef DEBUG
1940 xmlGenericError(xmlGenericErrorContext,
1941 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
1942 val->name);
1943#endif
1944 return;
1945 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001946 if ((cur->nodeTab[i] != NULL) &&
1947 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
1948 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001949 cur->nodeNr--;
1950 for (;i < cur->nodeNr;i++)
1951 cur->nodeTab[i] = cur->nodeTab[i + 1];
1952 cur->nodeTab[cur->nodeNr] = NULL;
1953}
1954
1955/**
1956 * xmlXPathNodeSetRemove:
1957 * @cur: the initial node set
1958 * @val: the index to remove
1959 *
1960 * Removes an entry from an existing NodeSet list.
1961 */
1962void
1963xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
1964 if (cur == NULL) return;
1965 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001966 if ((cur->nodeTab[val] != NULL) &&
1967 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
1968 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00001969 cur->nodeNr--;
1970 for (;val < cur->nodeNr;val++)
1971 cur->nodeTab[val] = cur->nodeTab[val + 1];
1972 cur->nodeTab[cur->nodeNr] = NULL;
1973}
1974
1975/**
1976 * xmlXPathFreeNodeSet:
1977 * @obj: the xmlNodeSetPtr to free
1978 *
1979 * Free the NodeSet compound (not the actual nodes !).
1980 */
1981void
1982xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
1983 if (obj == NULL) return;
1984 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001985 int i;
1986
1987 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1988 for (i = 0;i < obj->nodeNr;i++)
1989 if ((obj->nodeTab[i] != NULL) &&
1990 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
1991 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001992 xmlFree(obj->nodeTab);
1993 }
Owen Taylor3473f882001-02-23 17:55:21 +00001994 xmlFree(obj);
1995}
1996
1997/**
1998 * xmlXPathFreeValueTree:
1999 * @obj: the xmlNodeSetPtr to free
2000 *
2001 * Free the NodeSet compound and the actual tree, this is different
2002 * from xmlXPathFreeNodeSet()
2003 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002004static void
Owen Taylor3473f882001-02-23 17:55:21 +00002005xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
2006 int i;
2007
2008 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002009
2010 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002011 for (i = 0;i < obj->nodeNr;i++) {
2012 if (obj->nodeTab[i] != NULL) {
2013 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2014 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
2015 } else {
2016 xmlFreeNodeList(obj->nodeTab[i]);
2017 }
2018 }
2019 }
Owen Taylor3473f882001-02-23 17:55:21 +00002020 xmlFree(obj->nodeTab);
2021 }
Owen Taylor3473f882001-02-23 17:55:21 +00002022 xmlFree(obj);
2023}
2024
2025#if defined(DEBUG) || defined(DEBUG_STEP)
2026/**
2027 * xmlGenericErrorContextNodeSet:
2028 * @output: a FILE * for the output
2029 * @obj: the xmlNodeSetPtr to free
2030 *
2031 * Quick display of a NodeSet
2032 */
2033void
2034xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
2035 int i;
2036
2037 if (output == NULL) output = xmlGenericErrorContext;
2038 if (obj == NULL) {
2039 fprintf(output, "NodeSet == NULL !\n");
2040 return;
2041 }
2042 if (obj->nodeNr == 0) {
2043 fprintf(output, "NodeSet is empty\n");
2044 return;
2045 }
2046 if (obj->nodeTab == NULL) {
2047 fprintf(output, " nodeTab == NULL !\n");
2048 return;
2049 }
2050 for (i = 0; i < obj->nodeNr; i++) {
2051 if (obj->nodeTab[i] == NULL) {
2052 fprintf(output, " NULL !\n");
2053 return;
2054 }
2055 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
2056 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
2057 fprintf(output, " /");
2058 else if (obj->nodeTab[i]->name == NULL)
2059 fprintf(output, " noname!");
2060 else fprintf(output, " %s", obj->nodeTab[i]->name);
2061 }
2062 fprintf(output, "\n");
2063}
2064#endif
2065
2066/**
2067 * xmlXPathNewNodeSet:
2068 * @val: the NodePtr value
2069 *
2070 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2071 * it with the single Node @val
2072 *
2073 * Returns the newly created object.
2074 */
2075xmlXPathObjectPtr
2076xmlXPathNewNodeSet(xmlNodePtr val) {
2077 xmlXPathObjectPtr ret;
2078
2079 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2080 if (ret == NULL) {
2081 xmlGenericError(xmlGenericErrorContext,
2082 "xmlXPathNewNodeSet: out of memory\n");
2083 return(NULL);
2084 }
2085 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2086 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00002087 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002088 ret->nodesetval = xmlXPathNodeSetCreate(val);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002089 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002090 return(ret);
2091}
2092
2093/**
2094 * xmlXPathNewValueTree:
2095 * @val: the NodePtr value
2096 *
2097 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
2098 * it with the tree root @val
2099 *
2100 * Returns the newly created object.
2101 */
2102xmlXPathObjectPtr
2103xmlXPathNewValueTree(xmlNodePtr val) {
2104 xmlXPathObjectPtr ret;
2105
2106 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2107 if (ret == NULL) {
2108 xmlGenericError(xmlGenericErrorContext,
2109 "xmlXPathNewNodeSet: out of memory\n");
2110 return(NULL);
2111 }
2112 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2113 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002114 ret->boolval = 1;
2115 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00002116 ret->nodesetval = xmlXPathNodeSetCreate(val);
2117 return(ret);
2118}
2119
2120/**
2121 * xmlXPathNewNodeSetList:
2122 * @val: an existing NodeSet
2123 *
2124 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2125 * it with the Nodeset @val
2126 *
2127 * Returns the newly created object.
2128 */
2129xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002130xmlXPathNewNodeSetList(xmlNodeSetPtr val)
2131{
Owen Taylor3473f882001-02-23 17:55:21 +00002132 xmlXPathObjectPtr ret;
2133 int i;
2134
2135 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002136 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002137 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002138 ret = xmlXPathNewNodeSet(NULL);
2139 else {
2140 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
2141 for (i = 1; i < val->nodeNr; ++i)
2142 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2143 }
Owen Taylor3473f882001-02-23 17:55:21 +00002144
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002145 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002146}
2147
2148/**
2149 * xmlXPathWrapNodeSet:
2150 * @val: the NodePtr value
2151 *
2152 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2153 *
2154 * Returns the newly created object.
2155 */
2156xmlXPathObjectPtr
2157xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2158 xmlXPathObjectPtr ret;
2159
2160 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2161 if (ret == NULL) {
2162 xmlGenericError(xmlGenericErrorContext,
2163 "xmlXPathWrapNodeSet: out of memory\n");
2164 return(NULL);
2165 }
2166 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2167 ret->type = XPATH_NODESET;
2168 ret->nodesetval = val;
2169 return(ret);
2170}
2171
2172/**
2173 * xmlXPathFreeNodeSetList:
2174 * @obj: an existing NodeSetList object
2175 *
2176 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2177 * the list contrary to xmlXPathFreeObject().
2178 */
2179void
2180xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2181 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002182 xmlFree(obj);
2183}
2184
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002185/**
2186 * xmlXPathDifference:
2187 * @nodes1: a node-set
2188 * @nodes2: a node-set
2189 *
2190 * Implements the EXSLT - Sets difference() function:
2191 * node-set set:difference (node-set, node-set)
2192 *
2193 * Returns the difference between the two node sets, or nodes1 if
2194 * nodes2 is empty
2195 */
2196xmlNodeSetPtr
2197xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2198 xmlNodeSetPtr ret;
2199 int i, l1;
2200 xmlNodePtr cur;
2201
2202 if (xmlXPathNodeSetIsEmpty(nodes2))
2203 return(nodes1);
2204
2205 ret = xmlXPathNodeSetCreate(NULL);
2206 if (xmlXPathNodeSetIsEmpty(nodes1))
2207 return(ret);
2208
2209 l1 = xmlXPathNodeSetGetLength(nodes1);
2210
2211 for (i = 0; i < l1; i++) {
2212 cur = xmlXPathNodeSetItem(nodes1, i);
2213 if (!xmlXPathNodeSetContains(nodes2, cur))
2214 xmlXPathNodeSetAddUnique(ret, cur);
2215 }
2216 return(ret);
2217}
2218
2219/**
2220 * xmlXPathIntersection:
2221 * @nodes1: a node-set
2222 * @nodes2: a node-set
2223 *
2224 * Implements the EXSLT - Sets intersection() function:
2225 * node-set set:intersection (node-set, node-set)
2226 *
2227 * Returns a node set comprising the nodes that are within both the
2228 * node sets passed as arguments
2229 */
2230xmlNodeSetPtr
2231xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2232 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2233 int i, l1;
2234 xmlNodePtr cur;
2235
2236 if (xmlXPathNodeSetIsEmpty(nodes1))
2237 return(ret);
2238 if (xmlXPathNodeSetIsEmpty(nodes2))
2239 return(ret);
2240
2241 l1 = xmlXPathNodeSetGetLength(nodes1);
2242
2243 for (i = 0; i < l1; i++) {
2244 cur = xmlXPathNodeSetItem(nodes1, i);
2245 if (xmlXPathNodeSetContains(nodes2, cur))
2246 xmlXPathNodeSetAddUnique(ret, cur);
2247 }
2248 return(ret);
2249}
2250
2251/**
2252 * xmlXPathDistinctSorted:
2253 * @nodes: a node-set, sorted by document order
2254 *
2255 * Implements the EXSLT - Sets distinct() function:
2256 * node-set set:distinct (node-set)
2257 *
2258 * Returns a subset of the nodes contained in @nodes, or @nodes if
2259 * it is empty
2260 */
2261xmlNodeSetPtr
2262xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2263 xmlNodeSetPtr ret;
2264 xmlHashTablePtr hash;
2265 int i, l;
2266 xmlChar * strval;
2267 xmlNodePtr cur;
2268
2269 if (xmlXPathNodeSetIsEmpty(nodes))
2270 return(nodes);
2271
2272 ret = xmlXPathNodeSetCreate(NULL);
2273 l = xmlXPathNodeSetGetLength(nodes);
2274 hash = xmlHashCreate (l);
2275 for (i = 0; i < l; i++) {
2276 cur = xmlXPathNodeSetItem(nodes, i);
2277 strval = xmlXPathCastNodeToString(cur);
2278 if (xmlHashLookup(hash, strval) == NULL) {
2279 xmlHashAddEntry(hash, strval, strval);
2280 xmlXPathNodeSetAddUnique(ret, cur);
2281 } else {
2282 xmlFree(strval);
2283 }
2284 }
2285 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2286 return(ret);
2287}
2288
2289/**
2290 * xmlXPathDistinct:
2291 * @nodes: a node-set
2292 *
2293 * Implements the EXSLT - Sets distinct() function:
2294 * node-set set:distinct (node-set)
2295 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2296 * is called with the sorted node-set
2297 *
2298 * Returns a subset of the nodes contained in @nodes, or @nodes if
2299 * it is empty
2300 */
2301xmlNodeSetPtr
2302xmlXPathDistinct (xmlNodeSetPtr nodes) {
2303 if (xmlXPathNodeSetIsEmpty(nodes))
2304 return(nodes);
2305
2306 xmlXPathNodeSetSort(nodes);
2307 return(xmlXPathDistinctSorted(nodes));
2308}
2309
2310/**
2311 * xmlXPathHasSameNodes:
2312 * @nodes1: a node-set
2313 * @nodes2: a node-set
2314 *
2315 * Implements the EXSLT - Sets has-same-nodes function:
2316 * boolean set:has-same-node(node-set, node-set)
2317 *
2318 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2319 * otherwise
2320 */
2321int
2322xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2323 int i, l;
2324 xmlNodePtr cur;
2325
2326 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2327 xmlXPathNodeSetIsEmpty(nodes2))
2328 return(0);
2329
2330 l = xmlXPathNodeSetGetLength(nodes1);
2331 for (i = 0; i < l; i++) {
2332 cur = xmlXPathNodeSetItem(nodes1, i);
2333 if (xmlXPathNodeSetContains(nodes2, cur))
2334 return(1);
2335 }
2336 return(0);
2337}
2338
2339/**
2340 * xmlXPathNodeLeadingSorted:
2341 * @nodes: a node-set, sorted by document order
2342 * @node: a node
2343 *
2344 * Implements the EXSLT - Sets leading() function:
2345 * node-set set:leading (node-set, node-set)
2346 *
2347 * Returns the nodes in @nodes that precede @node in document order,
2348 * @nodes if @node is NULL or an empty node-set if @nodes
2349 * doesn't contain @node
2350 */
2351xmlNodeSetPtr
2352xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2353 int i, l;
2354 xmlNodePtr cur;
2355 xmlNodeSetPtr ret;
2356
2357 if (node == NULL)
2358 return(nodes);
2359
2360 ret = xmlXPathNodeSetCreate(NULL);
2361 if (xmlXPathNodeSetIsEmpty(nodes) ||
2362 (!xmlXPathNodeSetContains(nodes, node)))
2363 return(ret);
2364
2365 l = xmlXPathNodeSetGetLength(nodes);
2366 for (i = 0; i < l; i++) {
2367 cur = xmlXPathNodeSetItem(nodes, i);
2368 if (cur == node)
2369 break;
2370 xmlXPathNodeSetAddUnique(ret, cur);
2371 }
2372 return(ret);
2373}
2374
2375/**
2376 * xmlXPathNodeLeading:
2377 * @nodes: a node-set
2378 * @node: a node
2379 *
2380 * Implements the EXSLT - Sets leading() function:
2381 * node-set set:leading (node-set, node-set)
2382 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2383 * is called.
2384 *
2385 * Returns the nodes in @nodes that precede @node in document order,
2386 * @nodes if @node is NULL or an empty node-set if @nodes
2387 * doesn't contain @node
2388 */
2389xmlNodeSetPtr
2390xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2391 xmlXPathNodeSetSort(nodes);
2392 return(xmlXPathNodeLeadingSorted(nodes, node));
2393}
2394
2395/**
2396 * xmlXPathLeadingSorted:
2397 * @nodes1: a node-set, sorted by document order
2398 * @nodes2: a node-set, sorted by document order
2399 *
2400 * Implements the EXSLT - Sets leading() function:
2401 * node-set set:leading (node-set, node-set)
2402 *
2403 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2404 * in document order, @nodes1 if @nodes2 is NULL or empty or
2405 * an empty node-set if @nodes1 doesn't contain @nodes2
2406 */
2407xmlNodeSetPtr
2408xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2409 if (xmlXPathNodeSetIsEmpty(nodes2))
2410 return(nodes1);
2411 return(xmlXPathNodeLeadingSorted(nodes1,
2412 xmlXPathNodeSetItem(nodes2, 1)));
2413}
2414
2415/**
2416 * xmlXPathLeading:
2417 * @nodes1: a node-set
2418 * @nodes2: a node-set
2419 *
2420 * Implements the EXSLT - Sets leading() function:
2421 * node-set set:leading (node-set, node-set)
2422 * @nodes1 and @nodes2 are sorted by document order, then
2423 * #exslSetsLeadingSorted is called.
2424 *
2425 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2426 * in document order, @nodes1 if @nodes2 is NULL or empty or
2427 * an empty node-set if @nodes1 doesn't contain @nodes2
2428 */
2429xmlNodeSetPtr
2430xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2431 if (xmlXPathNodeSetIsEmpty(nodes2))
2432 return(nodes1);
2433 if (xmlXPathNodeSetIsEmpty(nodes1))
2434 return(xmlXPathNodeSetCreate(NULL));
2435 xmlXPathNodeSetSort(nodes1);
2436 xmlXPathNodeSetSort(nodes2);
2437 return(xmlXPathNodeLeadingSorted(nodes1,
2438 xmlXPathNodeSetItem(nodes2, 1)));
2439}
2440
2441/**
2442 * xmlXPathNodeTrailingSorted:
2443 * @nodes: a node-set, sorted by document order
2444 * @node: a node
2445 *
2446 * Implements the EXSLT - Sets trailing() function:
2447 * node-set set:trailing (node-set, node-set)
2448 *
2449 * Returns the nodes in @nodes that follow @node in document order,
2450 * @nodes if @node is NULL or an empty node-set if @nodes
2451 * doesn't contain @node
2452 */
2453xmlNodeSetPtr
2454xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2455 int i, l;
2456 xmlNodePtr cur;
2457 xmlNodeSetPtr ret;
2458
2459 if (node == NULL)
2460 return(nodes);
2461
2462 ret = xmlXPathNodeSetCreate(NULL);
2463 if (xmlXPathNodeSetIsEmpty(nodes) ||
2464 (!xmlXPathNodeSetContains(nodes, node)))
2465 return(ret);
2466
2467 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002468 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002469 cur = xmlXPathNodeSetItem(nodes, i);
2470 if (cur == node)
2471 break;
2472 xmlXPathNodeSetAddUnique(ret, cur);
2473 }
2474 return(ret);
2475}
2476
2477/**
2478 * xmlXPathNodeTrailing:
2479 * @nodes: a node-set
2480 * @node: a node
2481 *
2482 * Implements the EXSLT - Sets trailing() function:
2483 * node-set set:trailing (node-set, node-set)
2484 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2485 * is called.
2486 *
2487 * Returns the nodes in @nodes that follow @node in document order,
2488 * @nodes if @node is NULL or an empty node-set if @nodes
2489 * doesn't contain @node
2490 */
2491xmlNodeSetPtr
2492xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2493 xmlXPathNodeSetSort(nodes);
2494 return(xmlXPathNodeTrailingSorted(nodes, node));
2495}
2496
2497/**
2498 * xmlXPathTrailingSorted:
2499 * @nodes1: a node-set, sorted by document order
2500 * @nodes2: a node-set, sorted by document order
2501 *
2502 * Implements the EXSLT - Sets trailing() function:
2503 * node-set set:trailing (node-set, node-set)
2504 *
2505 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2506 * in document order, @nodes1 if @nodes2 is NULL or empty or
2507 * an empty node-set if @nodes1 doesn't contain @nodes2
2508 */
2509xmlNodeSetPtr
2510xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2511 if (xmlXPathNodeSetIsEmpty(nodes2))
2512 return(nodes1);
2513 return(xmlXPathNodeTrailingSorted(nodes1,
2514 xmlXPathNodeSetItem(nodes2, 0)));
2515}
2516
2517/**
2518 * xmlXPathTrailing:
2519 * @nodes1: a node-set
2520 * @nodes2: a node-set
2521 *
2522 * Implements the EXSLT - Sets trailing() function:
2523 * node-set set:trailing (node-set, node-set)
2524 * @nodes1 and @nodes2 are sorted by document order, then
2525 * #xmlXPathTrailingSorted is called.
2526 *
2527 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2528 * in document order, @nodes1 if @nodes2 is NULL or empty or
2529 * an empty node-set if @nodes1 doesn't contain @nodes2
2530 */
2531xmlNodeSetPtr
2532xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2533 if (xmlXPathNodeSetIsEmpty(nodes2))
2534 return(nodes1);
2535 if (xmlXPathNodeSetIsEmpty(nodes1))
2536 return(xmlXPathNodeSetCreate(NULL));
2537 xmlXPathNodeSetSort(nodes1);
2538 xmlXPathNodeSetSort(nodes2);
2539 return(xmlXPathNodeTrailingSorted(nodes1,
2540 xmlXPathNodeSetItem(nodes2, 0)));
2541}
2542
Owen Taylor3473f882001-02-23 17:55:21 +00002543/************************************************************************
2544 * *
2545 * Routines to handle extra functions *
2546 * *
2547 ************************************************************************/
2548
2549/**
2550 * xmlXPathRegisterFunc:
2551 * @ctxt: the XPath context
2552 * @name: the function name
2553 * @f: the function implementation or NULL
2554 *
2555 * Register a new function. If @f is NULL it unregisters the function
2556 *
2557 * Returns 0 in case of success, -1 in case of error
2558 */
2559int
2560xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2561 xmlXPathFunction f) {
2562 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2563}
2564
2565/**
2566 * xmlXPathRegisterFuncNS:
2567 * @ctxt: the XPath context
2568 * @name: the function name
2569 * @ns_uri: the function namespace URI
2570 * @f: the function implementation or NULL
2571 *
2572 * Register a new function. If @f is NULL it unregisters the function
2573 *
2574 * Returns 0 in case of success, -1 in case of error
2575 */
2576int
2577xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2578 const xmlChar *ns_uri, xmlXPathFunction f) {
2579 if (ctxt == NULL)
2580 return(-1);
2581 if (name == NULL)
2582 return(-1);
2583
2584 if (ctxt->funcHash == NULL)
2585 ctxt->funcHash = xmlHashCreate(0);
2586 if (ctxt->funcHash == NULL)
2587 return(-1);
2588 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2589}
2590
2591/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002592 * xmlXPathRegisterFuncLookup:
2593 * @ctxt: the XPath context
2594 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002595 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00002596 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002597 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00002598 */
2599void
2600xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2601 xmlXPathFuncLookupFunc f,
2602 void *funcCtxt) {
2603 if (ctxt == NULL)
2604 return;
2605 ctxt->funcLookupFunc = (void *) f;
2606 ctxt->funcLookupData = funcCtxt;
2607}
2608
2609/**
Owen Taylor3473f882001-02-23 17:55:21 +00002610 * xmlXPathFunctionLookup:
2611 * @ctxt: the XPath context
2612 * @name: the function name
2613 *
2614 * Search in the Function array of the context for the given
2615 * function.
2616 *
2617 * Returns the xmlXPathFunction or NULL if not found
2618 */
2619xmlXPathFunction
2620xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002621 if (ctxt == NULL)
2622 return (NULL);
2623
2624 if (ctxt->funcLookupFunc != NULL) {
2625 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002626 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002627
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002628 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002629 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002630 if (ret != NULL)
2631 return(ret);
2632 }
Owen Taylor3473f882001-02-23 17:55:21 +00002633 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2634}
2635
2636/**
2637 * xmlXPathFunctionLookupNS:
2638 * @ctxt: the XPath context
2639 * @name: the function name
2640 * @ns_uri: the function namespace URI
2641 *
2642 * Search in the Function array of the context for the given
2643 * function.
2644 *
2645 * Returns the xmlXPathFunction or NULL if not found
2646 */
2647xmlXPathFunction
2648xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2649 const xmlChar *ns_uri) {
2650 if (ctxt == NULL)
2651 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002652 if (name == NULL)
2653 return(NULL);
2654
Thomas Broyerba4ad322001-07-26 16:55:21 +00002655 if (ctxt->funcLookupFunc != NULL) {
2656 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002657 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002658
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002659 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002660 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002661 if (ret != NULL)
2662 return(ret);
2663 }
2664
2665 if (ctxt->funcHash == NULL)
2666 return(NULL);
2667
Owen Taylor3473f882001-02-23 17:55:21 +00002668 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2669}
2670
2671/**
2672 * xmlXPathRegisteredFuncsCleanup:
2673 * @ctxt: the XPath context
2674 *
2675 * Cleanup the XPath context data associated to registered functions
2676 */
2677void
2678xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2679 if (ctxt == NULL)
2680 return;
2681
2682 xmlHashFree(ctxt->funcHash, NULL);
2683 ctxt->funcHash = NULL;
2684}
2685
2686/************************************************************************
2687 * *
2688 * Routines to handle Variable *
2689 * *
2690 ************************************************************************/
2691
2692/**
2693 * xmlXPathRegisterVariable:
2694 * @ctxt: the XPath context
2695 * @name: the variable name
2696 * @value: the variable value or NULL
2697 *
2698 * Register a new variable value. If @value is NULL it unregisters
2699 * the variable
2700 *
2701 * Returns 0 in case of success, -1 in case of error
2702 */
2703int
2704xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2705 xmlXPathObjectPtr value) {
2706 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2707}
2708
2709/**
2710 * xmlXPathRegisterVariableNS:
2711 * @ctxt: the XPath context
2712 * @name: the variable name
2713 * @ns_uri: the variable namespace URI
2714 * @value: the variable value or NULL
2715 *
2716 * Register a new variable value. If @value is NULL it unregisters
2717 * the variable
2718 *
2719 * Returns 0 in case of success, -1 in case of error
2720 */
2721int
2722xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2723 const xmlChar *ns_uri,
2724 xmlXPathObjectPtr value) {
2725 if (ctxt == NULL)
2726 return(-1);
2727 if (name == NULL)
2728 return(-1);
2729
2730 if (ctxt->varHash == NULL)
2731 ctxt->varHash = xmlHashCreate(0);
2732 if (ctxt->varHash == NULL)
2733 return(-1);
2734 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2735 (void *) value,
2736 (xmlHashDeallocator)xmlXPathFreeObject));
2737}
2738
2739/**
2740 * xmlXPathRegisterVariableLookup:
2741 * @ctxt: the XPath context
2742 * @f: the lookup function
2743 * @data: the lookup data
2744 *
2745 * register an external mechanism to do variable lookup
2746 */
2747void
2748xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2749 xmlXPathVariableLookupFunc f, void *data) {
2750 if (ctxt == NULL)
2751 return;
2752 ctxt->varLookupFunc = (void *) f;
2753 ctxt->varLookupData = data;
2754}
2755
2756/**
2757 * xmlXPathVariableLookup:
2758 * @ctxt: the XPath context
2759 * @name: the variable name
2760 *
2761 * Search in the Variable array of the context for the given
2762 * variable value.
2763 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002764 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002765 */
2766xmlXPathObjectPtr
2767xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2768 if (ctxt == NULL)
2769 return(NULL);
2770
2771 if (ctxt->varLookupFunc != NULL) {
2772 xmlXPathObjectPtr ret;
2773
2774 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2775 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00002776 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002777 }
2778 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
2779}
2780
2781/**
2782 * xmlXPathVariableLookupNS:
2783 * @ctxt: the XPath context
2784 * @name: the variable name
2785 * @ns_uri: the variable namespace URI
2786 *
2787 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00002788 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00002789 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002790 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002791 */
2792xmlXPathObjectPtr
2793xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2794 const xmlChar *ns_uri) {
2795 if (ctxt == NULL)
2796 return(NULL);
2797
2798 if (ctxt->varLookupFunc != NULL) {
2799 xmlXPathObjectPtr ret;
2800
2801 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2802 (ctxt->varLookupData, name, ns_uri);
2803 if (ret != NULL) return(ret);
2804 }
2805
2806 if (ctxt->varHash == NULL)
2807 return(NULL);
2808 if (name == NULL)
2809 return(NULL);
2810
Daniel Veillard8c357d52001-07-03 23:43:33 +00002811 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
2812 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00002813}
2814
2815/**
2816 * xmlXPathRegisteredVariablesCleanup:
2817 * @ctxt: the XPath context
2818 *
2819 * Cleanup the XPath context data associated to registered variables
2820 */
2821void
2822xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
2823 if (ctxt == NULL)
2824 return;
2825
Daniel Veillard76d66f42001-05-16 21:05:17 +00002826 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00002827 ctxt->varHash = NULL;
2828}
2829
2830/**
2831 * xmlXPathRegisterNs:
2832 * @ctxt: the XPath context
2833 * @prefix: the namespace prefix
2834 * @ns_uri: the namespace name
2835 *
2836 * Register a new namespace. If @ns_uri is NULL it unregisters
2837 * the namespace
2838 *
2839 * Returns 0 in case of success, -1 in case of error
2840 */
2841int
2842xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
2843 const xmlChar *ns_uri) {
2844 if (ctxt == NULL)
2845 return(-1);
2846 if (prefix == NULL)
2847 return(-1);
2848
2849 if (ctxt->nsHash == NULL)
2850 ctxt->nsHash = xmlHashCreate(10);
2851 if (ctxt->nsHash == NULL)
2852 return(-1);
Daniel Veillard42766c02002-08-22 20:52:17 +00002853 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00002854 (xmlHashDeallocator)xmlFree));
2855}
2856
2857/**
2858 * xmlXPathNsLookup:
2859 * @ctxt: the XPath context
2860 * @prefix: the namespace prefix value
2861 *
2862 * Search in the namespace declaration array of the context for the given
2863 * namespace name associated to the given prefix
2864 *
2865 * Returns the value or NULL if not found
2866 */
2867const xmlChar *
2868xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
2869 if (ctxt == NULL)
2870 return(NULL);
2871 if (prefix == NULL)
2872 return(NULL);
2873
2874#ifdef XML_XML_NAMESPACE
2875 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
2876 return(XML_XML_NAMESPACE);
2877#endif
2878
Daniel Veillardc8f620b2001-04-30 20:31:33 +00002879 if (ctxt->namespaces != NULL) {
2880 int i;
2881
2882 for (i = 0;i < ctxt->nsNr;i++) {
2883 if ((ctxt->namespaces[i] != NULL) &&
2884 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
2885 return(ctxt->namespaces[i]->href);
2886 }
2887 }
Owen Taylor3473f882001-02-23 17:55:21 +00002888
2889 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
2890}
2891
2892/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002893 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00002894 * @ctxt: the XPath context
2895 *
2896 * Cleanup the XPath context data associated to registered variables
2897 */
2898void
2899xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
2900 if (ctxt == NULL)
2901 return;
2902
Daniel Veillard42766c02002-08-22 20:52:17 +00002903 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00002904 ctxt->nsHash = NULL;
2905}
2906
2907/************************************************************************
2908 * *
2909 * Routines to handle Values *
2910 * *
2911 ************************************************************************/
2912
2913/* Allocations are terrible, one need to optimize all this !!! */
2914
2915/**
2916 * xmlXPathNewFloat:
2917 * @val: the double value
2918 *
2919 * Create a new xmlXPathObjectPtr of type double and of value @val
2920 *
2921 * Returns the newly created object.
2922 */
2923xmlXPathObjectPtr
2924xmlXPathNewFloat(double val) {
2925 xmlXPathObjectPtr ret;
2926
2927 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2928 if (ret == NULL) {
2929 xmlGenericError(xmlGenericErrorContext,
2930 "xmlXPathNewFloat: out of memory\n");
2931 return(NULL);
2932 }
2933 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2934 ret->type = XPATH_NUMBER;
2935 ret->floatval = val;
2936 return(ret);
2937}
2938
2939/**
2940 * xmlXPathNewBoolean:
2941 * @val: the boolean value
2942 *
2943 * Create a new xmlXPathObjectPtr of type boolean and of value @val
2944 *
2945 * Returns the newly created object.
2946 */
2947xmlXPathObjectPtr
2948xmlXPathNewBoolean(int val) {
2949 xmlXPathObjectPtr ret;
2950
2951 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2952 if (ret == NULL) {
2953 xmlGenericError(xmlGenericErrorContext,
2954 "xmlXPathNewBoolean: out of memory\n");
2955 return(NULL);
2956 }
2957 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2958 ret->type = XPATH_BOOLEAN;
2959 ret->boolval = (val != 0);
2960 return(ret);
2961}
2962
2963/**
2964 * xmlXPathNewString:
2965 * @val: the xmlChar * value
2966 *
2967 * Create a new xmlXPathObjectPtr of type string and of value @val
2968 *
2969 * Returns the newly created object.
2970 */
2971xmlXPathObjectPtr
2972xmlXPathNewString(const xmlChar *val) {
2973 xmlXPathObjectPtr ret;
2974
2975 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2976 if (ret == NULL) {
2977 xmlGenericError(xmlGenericErrorContext,
2978 "xmlXPathNewString: out of memory\n");
2979 return(NULL);
2980 }
2981 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2982 ret->type = XPATH_STRING;
2983 if (val != NULL)
2984 ret->stringval = xmlStrdup(val);
2985 else
2986 ret->stringval = xmlStrdup((const xmlChar *)"");
2987 return(ret);
2988}
2989
2990/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002991 * xmlXPathWrapString:
2992 * @val: the xmlChar * value
2993 *
2994 * Wraps the @val string into an XPath object.
2995 *
2996 * Returns the newly created object.
2997 */
2998xmlXPathObjectPtr
2999xmlXPathWrapString (xmlChar *val) {
3000 xmlXPathObjectPtr ret;
3001
3002 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3003 if (ret == NULL) {
3004 xmlGenericError(xmlGenericErrorContext,
3005 "xmlXPathWrapString: out of memory\n");
3006 return(NULL);
3007 }
3008 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3009 ret->type = XPATH_STRING;
3010 ret->stringval = val;
3011 return(ret);
3012}
3013
3014/**
Owen Taylor3473f882001-02-23 17:55:21 +00003015 * xmlXPathNewCString:
3016 * @val: the char * value
3017 *
3018 * Create a new xmlXPathObjectPtr of type string and of value @val
3019 *
3020 * Returns the newly created object.
3021 */
3022xmlXPathObjectPtr
3023xmlXPathNewCString(const char *val) {
3024 xmlXPathObjectPtr ret;
3025
3026 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3027 if (ret == NULL) {
3028 xmlGenericError(xmlGenericErrorContext,
3029 "xmlXPathNewCString: out of memory\n");
3030 return(NULL);
3031 }
3032 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3033 ret->type = XPATH_STRING;
3034 ret->stringval = xmlStrdup(BAD_CAST val);
3035 return(ret);
3036}
3037
3038/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003039 * xmlXPathWrapCString:
3040 * @val: the char * value
3041 *
3042 * Wraps a string into an XPath object.
3043 *
3044 * Returns the newly created object.
3045 */
3046xmlXPathObjectPtr
3047xmlXPathWrapCString (char * val) {
3048 return(xmlXPathWrapString((xmlChar *)(val)));
3049}
3050
3051/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003052 * xmlXPathWrapExternal:
3053 * @val: the user data
3054 *
3055 * Wraps the @val data into an XPath object.
3056 *
3057 * Returns the newly created object.
3058 */
3059xmlXPathObjectPtr
3060xmlXPathWrapExternal (void *val) {
3061 xmlXPathObjectPtr ret;
3062
3063 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3064 if (ret == NULL) {
3065 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003066 "xmlXPathWrapExternal: out of memory\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003067 return(NULL);
3068 }
3069 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3070 ret->type = XPATH_USERS;
3071 ret->user = val;
3072 return(ret);
3073}
3074
3075/**
Owen Taylor3473f882001-02-23 17:55:21 +00003076 * xmlXPathObjectCopy:
3077 * @val: the original object
3078 *
3079 * allocate a new copy of a given object
3080 *
3081 * Returns the newly created object.
3082 */
3083xmlXPathObjectPtr
3084xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3085 xmlXPathObjectPtr ret;
3086
3087 if (val == NULL)
3088 return(NULL);
3089
3090 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3091 if (ret == NULL) {
3092 xmlGenericError(xmlGenericErrorContext,
3093 "xmlXPathObjectCopy: out of memory\n");
3094 return(NULL);
3095 }
3096 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3097 switch (val->type) {
3098 case XPATH_BOOLEAN:
3099 case XPATH_NUMBER:
3100 case XPATH_POINT:
3101 case XPATH_RANGE:
3102 break;
3103 case XPATH_STRING:
3104 ret->stringval = xmlStrdup(val->stringval);
3105 break;
3106 case XPATH_XSLT_TREE:
3107 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003108 (val->nodesetval->nodeTab != NULL)) {
3109 ret->boolval = 1;
Daniel Veillard6ab38382001-10-06 13:08:27 +00003110 ret->user = xmlDocCopyNode(val->nodesetval->nodeTab[0],
3111 val->nodesetval->nodeTab[0]->doc, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003112 ret->nodesetval = xmlXPathNodeSetCreate(
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003113 (xmlNodePtr) ret->user);
3114 } else
Owen Taylor3473f882001-02-23 17:55:21 +00003115 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003116 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00003117 break;
3118 case XPATH_NODESET:
3119 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003120 /* Do not deallocate the copied tree value */
3121 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003122 break;
3123 case XPATH_LOCATIONSET:
3124#ifdef LIBXML_XPTR_ENABLED
3125 {
3126 xmlLocationSetPtr loc = val->user;
3127 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3128 break;
3129 }
3130#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00003131 case XPATH_USERS:
3132 ret->user = val->user;
3133 break;
3134 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00003135 xmlGenericError(xmlGenericErrorContext,
3136 "xmlXPathObjectCopy: unsupported type %d\n",
3137 val->type);
3138 break;
3139 }
3140 return(ret);
3141}
3142
3143/**
3144 * xmlXPathFreeObject:
3145 * @obj: the object to free
3146 *
3147 * Free up an xmlXPathObjectPtr object.
3148 */
3149void
3150xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3151 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003152 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00003153 if (obj->boolval) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003154 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003155 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00003156 xmlFreeNodeList((xmlNodePtr) obj->user);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003157 } else if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00003158 xmlXPathFreeValueTree(obj->nodesetval);
3159 } else {
3160 if (obj->nodesetval != NULL)
3161 xmlXPathFreeNodeSet(obj->nodesetval);
3162 }
Owen Taylor3473f882001-02-23 17:55:21 +00003163#ifdef LIBXML_XPTR_ENABLED
3164 } else if (obj->type == XPATH_LOCATIONSET) {
3165 if (obj->user != NULL)
3166 xmlXPtrFreeLocationSet(obj->user);
3167#endif
3168 } else if (obj->type == XPATH_STRING) {
3169 if (obj->stringval != NULL)
3170 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00003171 }
3172
Owen Taylor3473f882001-02-23 17:55:21 +00003173 xmlFree(obj);
3174}
3175
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003176
3177/************************************************************************
3178 * *
3179 * Type Casting Routines *
3180 * *
3181 ************************************************************************/
3182
3183/**
3184 * xmlXPathCastBooleanToString:
3185 * @val: a boolean
3186 *
3187 * Converts a boolean to its string value.
3188 *
3189 * Returns a newly allocated string.
3190 */
3191xmlChar *
3192xmlXPathCastBooleanToString (int val) {
3193 xmlChar *ret;
3194 if (val)
3195 ret = xmlStrdup((const xmlChar *) "true");
3196 else
3197 ret = xmlStrdup((const xmlChar *) "false");
3198 return(ret);
3199}
3200
3201/**
3202 * xmlXPathCastNumberToString:
3203 * @val: a number
3204 *
3205 * Converts a number to its string value.
3206 *
3207 * Returns a newly allocated string.
3208 */
3209xmlChar *
3210xmlXPathCastNumberToString (double val) {
3211 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00003212 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003213 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003214 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003215 break;
3216 case -1:
3217 ret = xmlStrdup((const xmlChar *) "-Infinity");
3218 break;
3219 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003220 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003221 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00003222 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
3223 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003224 } else {
3225 /* could be improved */
3226 char buf[100];
3227 xmlXPathFormatNumber(val, buf, 100);
3228 ret = xmlStrdup((const xmlChar *) buf);
3229 }
3230 }
3231 return(ret);
3232}
3233
3234/**
3235 * xmlXPathCastNodeToString:
3236 * @node: a node
3237 *
3238 * Converts a node to its string value.
3239 *
3240 * Returns a newly allocated string.
3241 */
3242xmlChar *
3243xmlXPathCastNodeToString (xmlNodePtr node) {
Daniel Veillard23b1f372002-04-18 15:50:05 +00003244 if ((node != NULL) && (node->type == XML_DOCUMENT_NODE))
3245 node = xmlDocGetRootElement((xmlDocPtr) node);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003246 return(xmlNodeGetContent(node));
3247}
3248
3249/**
3250 * xmlXPathCastNodeSetToString:
3251 * @ns: a node-set
3252 *
3253 * Converts a node-set to its string value.
3254 *
3255 * Returns a newly allocated string.
3256 */
3257xmlChar *
3258xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3259 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3260 return(xmlStrdup((const xmlChar *) ""));
3261
3262 xmlXPathNodeSetSort(ns);
3263 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3264}
3265
3266/**
3267 * xmlXPathCastToString:
3268 * @val: an XPath object
3269 *
3270 * Converts an existing object to its string() equivalent
3271 *
3272 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003273 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003274 * string object).
3275 */
3276xmlChar *
3277xmlXPathCastToString(xmlXPathObjectPtr val) {
3278 xmlChar *ret = NULL;
3279
3280 if (val == NULL)
3281 return(xmlStrdup((const xmlChar *) ""));
3282 switch (val->type) {
3283 case XPATH_UNDEFINED:
3284#ifdef DEBUG_EXPR
3285 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3286#endif
3287 ret = xmlStrdup((const xmlChar *) "");
3288 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003289 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003290 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003291 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3292 break;
3293 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00003294 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003295 case XPATH_BOOLEAN:
3296 ret = xmlXPathCastBooleanToString(val->boolval);
3297 break;
3298 case XPATH_NUMBER: {
3299 ret = xmlXPathCastNumberToString(val->floatval);
3300 break;
3301 }
3302 case XPATH_USERS:
3303 case XPATH_POINT:
3304 case XPATH_RANGE:
3305 case XPATH_LOCATIONSET:
3306 TODO
3307 ret = xmlStrdup((const xmlChar *) "");
3308 break;
3309 }
3310 return(ret);
3311}
3312
3313/**
3314 * xmlXPathConvertString:
3315 * @val: an XPath object
3316 *
3317 * Converts an existing object to its string() equivalent
3318 *
3319 * Returns the new object, the old one is freed (or the operation
3320 * is done directly on @val)
3321 */
3322xmlXPathObjectPtr
3323xmlXPathConvertString(xmlXPathObjectPtr val) {
3324 xmlChar *res = NULL;
3325
3326 if (val == NULL)
3327 return(xmlXPathNewCString(""));
3328
3329 switch (val->type) {
3330 case XPATH_UNDEFINED:
3331#ifdef DEBUG_EXPR
3332 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3333#endif
3334 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003335 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003336 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003337 res = xmlXPathCastNodeSetToString(val->nodesetval);
3338 break;
3339 case XPATH_STRING:
3340 return(val);
3341 case XPATH_BOOLEAN:
3342 res = xmlXPathCastBooleanToString(val->boolval);
3343 break;
3344 case XPATH_NUMBER:
3345 res = xmlXPathCastNumberToString(val->floatval);
3346 break;
3347 case XPATH_USERS:
3348 case XPATH_POINT:
3349 case XPATH_RANGE:
3350 case XPATH_LOCATIONSET:
3351 TODO;
3352 break;
3353 }
3354 xmlXPathFreeObject(val);
3355 if (res == NULL)
3356 return(xmlXPathNewCString(""));
3357 return(xmlXPathWrapString(res));
3358}
3359
3360/**
3361 * xmlXPathCastBooleanToNumber:
3362 * @val: a boolean
3363 *
3364 * Converts a boolean to its number value
3365 *
3366 * Returns the number value
3367 */
3368double
3369xmlXPathCastBooleanToNumber(int val) {
3370 if (val)
3371 return(1.0);
3372 return(0.0);
3373}
3374
3375/**
3376 * xmlXPathCastStringToNumber:
3377 * @val: a string
3378 *
3379 * Converts a string to its number value
3380 *
3381 * Returns the number value
3382 */
3383double
3384xmlXPathCastStringToNumber(const xmlChar * val) {
3385 return(xmlXPathStringEvalNumber(val));
3386}
3387
3388/**
3389 * xmlXPathCastNodeToNumber:
3390 * @node: a node
3391 *
3392 * Converts a node to its number value
3393 *
3394 * Returns the number value
3395 */
3396double
3397xmlXPathCastNodeToNumber (xmlNodePtr node) {
3398 xmlChar *strval;
3399 double ret;
3400
3401 if (node == NULL)
3402 return(xmlXPathNAN);
3403 strval = xmlXPathCastNodeToString(node);
3404 if (strval == NULL)
3405 return(xmlXPathNAN);
3406 ret = xmlXPathCastStringToNumber(strval);
3407 xmlFree(strval);
3408
3409 return(ret);
3410}
3411
3412/**
3413 * xmlXPathCastNodeSetToNumber:
3414 * @ns: a node-set
3415 *
3416 * Converts a node-set to its number value
3417 *
3418 * Returns the number value
3419 */
3420double
3421xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3422 xmlChar *str;
3423 double ret;
3424
3425 if (ns == NULL)
3426 return(xmlXPathNAN);
3427 str = xmlXPathCastNodeSetToString(ns);
3428 ret = xmlXPathCastStringToNumber(str);
3429 xmlFree(str);
3430 return(ret);
3431}
3432
3433/**
3434 * xmlXPathCastToNumber:
3435 * @val: an XPath object
3436 *
3437 * Converts an XPath object to its number value
3438 *
3439 * Returns the number value
3440 */
3441double
3442xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3443 double ret = 0.0;
3444
3445 if (val == NULL)
3446 return(xmlXPathNAN);
3447 switch (val->type) {
3448 case XPATH_UNDEFINED:
3449#ifdef DEGUB_EXPR
3450 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3451#endif
3452 ret = xmlXPathNAN;
3453 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003454 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003455 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003456 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3457 break;
3458 case XPATH_STRING:
3459 ret = xmlXPathCastStringToNumber(val->stringval);
3460 break;
3461 case XPATH_NUMBER:
3462 ret = val->floatval;
3463 break;
3464 case XPATH_BOOLEAN:
3465 ret = xmlXPathCastBooleanToNumber(val->boolval);
3466 break;
3467 case XPATH_USERS:
3468 case XPATH_POINT:
3469 case XPATH_RANGE:
3470 case XPATH_LOCATIONSET:
3471 TODO;
3472 ret = xmlXPathNAN;
3473 break;
3474 }
3475 return(ret);
3476}
3477
3478/**
3479 * xmlXPathConvertNumber:
3480 * @val: an XPath object
3481 *
3482 * Converts an existing object to its number() equivalent
3483 *
3484 * Returns the new object, the old one is freed (or the operation
3485 * is done directly on @val)
3486 */
3487xmlXPathObjectPtr
3488xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3489 xmlXPathObjectPtr ret;
3490
3491 if (val == NULL)
3492 return(xmlXPathNewFloat(0.0));
3493 if (val->type == XPATH_NUMBER)
3494 return(val);
3495 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3496 xmlXPathFreeObject(val);
3497 return(ret);
3498}
3499
3500/**
3501 * xmlXPathCastNumberToBoolean:
3502 * @val: a number
3503 *
3504 * Converts a number to its boolean value
3505 *
3506 * Returns the boolean value
3507 */
3508int
3509xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003510 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003511 return(0);
3512 return(1);
3513}
3514
3515/**
3516 * xmlXPathCastStringToBoolean:
3517 * @val: a string
3518 *
3519 * Converts a string to its boolean value
3520 *
3521 * Returns the boolean value
3522 */
3523int
3524xmlXPathCastStringToBoolean (const xmlChar *val) {
3525 if ((val == NULL) || (xmlStrlen(val) == 0))
3526 return(0);
3527 return(1);
3528}
3529
3530/**
3531 * xmlXPathCastNodeSetToBoolean:
3532 * @ns: a node-set
3533 *
3534 * Converts a node-set to its boolean value
3535 *
3536 * Returns the boolean value
3537 */
3538int
3539xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3540 if ((ns == NULL) || (ns->nodeNr == 0))
3541 return(0);
3542 return(1);
3543}
3544
3545/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003546 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003547 * @val: an XPath object
3548 *
3549 * Converts an XPath object to its boolean value
3550 *
3551 * Returns the boolean value
3552 */
3553int
3554xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3555 int ret = 0;
3556
3557 if (val == NULL)
3558 return(0);
3559 switch (val->type) {
3560 case XPATH_UNDEFINED:
3561#ifdef DEBUG_EXPR
3562 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3563#endif
3564 ret = 0;
3565 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003566 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003567 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003568 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3569 break;
3570 case XPATH_STRING:
3571 ret = xmlXPathCastStringToBoolean(val->stringval);
3572 break;
3573 case XPATH_NUMBER:
3574 ret = xmlXPathCastNumberToBoolean(val->floatval);
3575 break;
3576 case XPATH_BOOLEAN:
3577 ret = val->boolval;
3578 break;
3579 case XPATH_USERS:
3580 case XPATH_POINT:
3581 case XPATH_RANGE:
3582 case XPATH_LOCATIONSET:
3583 TODO;
3584 ret = 0;
3585 break;
3586 }
3587 return(ret);
3588}
3589
3590
3591/**
3592 * xmlXPathConvertBoolean:
3593 * @val: an XPath object
3594 *
3595 * Converts an existing object to its boolean() equivalent
3596 *
3597 * Returns the new object, the old one is freed (or the operation
3598 * is done directly on @val)
3599 */
3600xmlXPathObjectPtr
3601xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3602 xmlXPathObjectPtr ret;
3603
3604 if (val == NULL)
3605 return(xmlXPathNewBoolean(0));
3606 if (val->type == XPATH_BOOLEAN)
3607 return(val);
3608 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3609 xmlXPathFreeObject(val);
3610 return(ret);
3611}
3612
Owen Taylor3473f882001-02-23 17:55:21 +00003613/************************************************************************
3614 * *
3615 * Routines to handle XPath contexts *
3616 * *
3617 ************************************************************************/
3618
3619/**
3620 * xmlXPathNewContext:
3621 * @doc: the XML document
3622 *
3623 * Create a new xmlXPathContext
3624 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00003625 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00003626 */
3627xmlXPathContextPtr
3628xmlXPathNewContext(xmlDocPtr doc) {
3629 xmlXPathContextPtr ret;
3630
3631 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3632 if (ret == NULL) {
3633 xmlGenericError(xmlGenericErrorContext,
3634 "xmlXPathNewContext: out of memory\n");
3635 return(NULL);
3636 }
3637 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3638 ret->doc = doc;
3639 ret->node = NULL;
3640
3641 ret->varHash = NULL;
3642
3643 ret->nb_types = 0;
3644 ret->max_types = 0;
3645 ret->types = NULL;
3646
3647 ret->funcHash = xmlHashCreate(0);
3648
3649 ret->nb_axis = 0;
3650 ret->max_axis = 0;
3651 ret->axis = NULL;
3652
3653 ret->nsHash = NULL;
3654 ret->user = NULL;
3655
3656 ret->contextSize = -1;
3657 ret->proximityPosition = -1;
3658
3659 xmlXPathRegisterAllFunctions(ret);
3660
3661 return(ret);
3662}
3663
3664/**
3665 * xmlXPathFreeContext:
3666 * @ctxt: the context to free
3667 *
3668 * Free up an xmlXPathContext
3669 */
3670void
3671xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3672 xmlXPathRegisteredNsCleanup(ctxt);
3673 xmlXPathRegisteredFuncsCleanup(ctxt);
3674 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003675 xmlFree(ctxt);
3676}
3677
3678/************************************************************************
3679 * *
3680 * Routines to handle XPath parser contexts *
3681 * *
3682 ************************************************************************/
3683
3684#define CHECK_CTXT(ctxt) \
3685 if (ctxt == NULL) { \
3686 xmlGenericError(xmlGenericErrorContext, \
3687 "%s:%d Internal error: ctxt == NULL\n", \
3688 __FILE__, __LINE__); \
3689 } \
3690
3691
3692#define CHECK_CONTEXT(ctxt) \
3693 if (ctxt == NULL) { \
3694 xmlGenericError(xmlGenericErrorContext, \
3695 "%s:%d Internal error: no context\n", \
3696 __FILE__, __LINE__); \
3697 } \
3698 else if (ctxt->doc == NULL) { \
3699 xmlGenericError(xmlGenericErrorContext, \
3700 "%s:%d Internal error: no document\n", \
3701 __FILE__, __LINE__); \
3702 } \
3703 else if (ctxt->doc->children == NULL) { \
3704 xmlGenericError(xmlGenericErrorContext, \
3705 "%s:%d Internal error: document without root\n", \
3706 __FILE__, __LINE__); \
3707 } \
3708
3709
3710/**
3711 * xmlXPathNewParserContext:
3712 * @str: the XPath expression
3713 * @ctxt: the XPath context
3714 *
3715 * Create a new xmlXPathParserContext
3716 *
3717 * Returns the xmlXPathParserContext just allocated.
3718 */
3719xmlXPathParserContextPtr
3720xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3721 xmlXPathParserContextPtr ret;
3722
3723 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3724 if (ret == NULL) {
3725 xmlGenericError(xmlGenericErrorContext,
3726 "xmlXPathNewParserContext: out of memory\n");
3727 return(NULL);
3728 }
3729 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3730 ret->cur = ret->base = str;
3731 ret->context = ctxt;
3732
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003733 ret->comp = xmlXPathNewCompExpr();
3734 if (ret->comp == NULL) {
3735 xmlFree(ret->valueTab);
3736 xmlFree(ret);
3737 return(NULL);
3738 }
3739
3740 return(ret);
3741}
3742
3743/**
3744 * xmlXPathCompParserContext:
3745 * @comp: the XPath compiled expression
3746 * @ctxt: the XPath context
3747 *
3748 * Create a new xmlXPathParserContext when processing a compiled expression
3749 *
3750 * Returns the xmlXPathParserContext just allocated.
3751 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003752static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003753xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3754 xmlXPathParserContextPtr ret;
3755
3756 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3757 if (ret == NULL) {
3758 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003759 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003760 return(NULL);
3761 }
3762 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3763
Owen Taylor3473f882001-02-23 17:55:21 +00003764 /* Allocate the value stack */
3765 ret->valueTab = (xmlXPathObjectPtr *)
3766 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003767 if (ret->valueTab == NULL) {
3768 xmlFree(ret);
3769 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003770 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003771 return(NULL);
3772 }
Owen Taylor3473f882001-02-23 17:55:21 +00003773 ret->valueNr = 0;
3774 ret->valueMax = 10;
3775 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003776
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00003777 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003778 ret->comp = comp;
3779
Owen Taylor3473f882001-02-23 17:55:21 +00003780 return(ret);
3781}
3782
3783/**
3784 * xmlXPathFreeParserContext:
3785 * @ctxt: the context to free
3786 *
3787 * Free up an xmlXPathParserContext
3788 */
3789void
3790xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
3791 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003792 xmlFree(ctxt->valueTab);
3793 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003794 if (ctxt->comp)
3795 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00003796 xmlFree(ctxt);
3797}
3798
3799/************************************************************************
3800 * *
3801 * The implicit core function library *
3802 * *
3803 ************************************************************************/
3804
Owen Taylor3473f882001-02-23 17:55:21 +00003805/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00003806 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00003807 * @node: a node pointer
3808 *
3809 * Function computing the beginning of the string value of the node,
3810 * used to speed up comparisons
3811 *
3812 * Returns an int usable as a hash
3813 */
3814static unsigned int
3815xmlXPathNodeValHash(xmlNodePtr node) {
3816 int len = 2;
3817 const xmlChar * string = NULL;
3818 xmlNodePtr tmp = NULL;
3819 unsigned int ret = 0;
3820
3821 if (node == NULL)
3822 return(0);
3823
3824
3825 switch (node->type) {
3826 case XML_COMMENT_NODE:
3827 case XML_PI_NODE:
3828 case XML_CDATA_SECTION_NODE:
3829 case XML_TEXT_NODE:
3830 string = node->content;
3831 if (string == NULL)
3832 return(0);
3833 if (string[0] == 0)
3834 return(0);
3835 return(((unsigned int) string[0]) +
3836 (((unsigned int) string[1]) << 8));
3837 case XML_NAMESPACE_DECL:
3838 string = ((xmlNsPtr)node)->href;
3839 if (string == NULL)
3840 return(0);
3841 if (string[0] == 0)
3842 return(0);
3843 return(((unsigned int) string[0]) +
3844 (((unsigned int) string[1]) << 8));
3845 case XML_ATTRIBUTE_NODE:
3846 tmp = ((xmlAttrPtr) node)->children;
3847 break;
3848 case XML_ELEMENT_NODE:
3849 tmp = node->children;
3850 break;
3851 default:
3852 return(0);
3853 }
3854 while (tmp != NULL) {
3855 switch (tmp->type) {
3856 case XML_COMMENT_NODE:
3857 case XML_PI_NODE:
3858 case XML_CDATA_SECTION_NODE:
3859 case XML_TEXT_NODE:
3860 string = tmp->content;
3861 break;
3862 case XML_NAMESPACE_DECL:
3863 string = ((xmlNsPtr)tmp)->href;
3864 break;
3865 default:
3866 break;
3867 }
3868 if ((string != NULL) && (string[0] != 0)) {
3869 if (string[0] == 0)
3870 return(0);
3871 if (len == 1) {
3872 return(ret + (((unsigned int) string[0]) << 8));
3873 }
3874 if (string[1] == 0) {
3875 len = 1;
3876 ret = (unsigned int) string[0];
3877 } else {
3878 return(((unsigned int) string[0]) +
3879 (((unsigned int) string[1]) << 8));
3880 }
3881 }
3882 /*
3883 * Skip to next node
3884 */
3885 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
3886 if (tmp->children->type != XML_ENTITY_DECL) {
3887 tmp = tmp->children;
3888 continue;
3889 }
3890 }
3891 if (tmp == node)
3892 break;
3893
3894 if (tmp->next != NULL) {
3895 tmp = tmp->next;
3896 continue;
3897 }
3898
3899 do {
3900 tmp = tmp->parent;
3901 if (tmp == NULL)
3902 break;
3903 if (tmp == node) {
3904 tmp = NULL;
3905 break;
3906 }
3907 if (tmp->next != NULL) {
3908 tmp = tmp->next;
3909 break;
3910 }
3911 } while (tmp != NULL);
3912 }
3913 return(ret);
3914}
3915
3916/**
3917 * xmlXPathStringHash:
3918 * @string: a string
3919 *
3920 * Function computing the beginning of the string value of the node,
3921 * used to speed up comparisons
3922 *
3923 * Returns an int usable as a hash
3924 */
3925static unsigned int
3926xmlXPathStringHash(const xmlChar * string) {
3927 if (string == NULL)
3928 return((unsigned int) 0);
3929 if (string[0] == 0)
3930 return(0);
3931 return(((unsigned int) string[0]) +
3932 (((unsigned int) string[1]) << 8));
3933}
3934
3935/**
Owen Taylor3473f882001-02-23 17:55:21 +00003936 * xmlXPathCompareNodeSetFloat:
3937 * @ctxt: the XPath Parser context
3938 * @inf: less than (1) or greater than (0)
3939 * @strict: is the comparison strict
3940 * @arg: the node set
3941 * @f: the value
3942 *
3943 * Implement the compare operation between a nodeset and a number
3944 * @ns < @val (1, 1, ...
3945 * @ns <= @val (1, 0, ...
3946 * @ns > @val (0, 1, ...
3947 * @ns >= @val (0, 0, ...
3948 *
3949 * If one object to be compared is a node-set and the other is a number,
3950 * then the comparison will be true if and only if there is a node in the
3951 * node-set such that the result of performing the comparison on the number
3952 * to be compared and on the result of converting the string-value of that
3953 * node to a number using the number function is true.
3954 *
3955 * Returns 0 or 1 depending on the results of the test.
3956 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003957static int
Owen Taylor3473f882001-02-23 17:55:21 +00003958xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
3959 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
3960 int i, ret = 0;
3961 xmlNodeSetPtr ns;
3962 xmlChar *str2;
3963
3964 if ((f == NULL) || (arg == NULL) ||
3965 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3966 xmlXPathFreeObject(arg);
3967 xmlXPathFreeObject(f);
3968 return(0);
3969 }
3970 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003971 if (ns != NULL) {
3972 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003973 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003974 if (str2 != NULL) {
3975 valuePush(ctxt,
3976 xmlXPathNewString(str2));
3977 xmlFree(str2);
3978 xmlXPathNumberFunction(ctxt, 1);
3979 valuePush(ctxt, xmlXPathObjectCopy(f));
3980 ret = xmlXPathCompareValues(ctxt, inf, strict);
3981 if (ret)
3982 break;
3983 }
3984 }
Owen Taylor3473f882001-02-23 17:55:21 +00003985 }
3986 xmlXPathFreeObject(arg);
3987 xmlXPathFreeObject(f);
3988 return(ret);
3989}
3990
3991/**
3992 * xmlXPathCompareNodeSetString:
3993 * @ctxt: the XPath Parser context
3994 * @inf: less than (1) or greater than (0)
3995 * @strict: is the comparison strict
3996 * @arg: the node set
3997 * @s: the value
3998 *
3999 * Implement the compare operation between a nodeset and a string
4000 * @ns < @val (1, 1, ...
4001 * @ns <= @val (1, 0, ...
4002 * @ns > @val (0, 1, ...
4003 * @ns >= @val (0, 0, ...
4004 *
4005 * If one object to be compared is a node-set and the other is a string,
4006 * then the comparison will be true if and only if there is a node in
4007 * the node-set such that the result of performing the comparison on the
4008 * string-value of the node and the other string is true.
4009 *
4010 * Returns 0 or 1 depending on the results of the test.
4011 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004012static int
Owen Taylor3473f882001-02-23 17:55:21 +00004013xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
4014 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
4015 int i, ret = 0;
4016 xmlNodeSetPtr ns;
4017 xmlChar *str2;
4018
4019 if ((s == NULL) || (arg == NULL) ||
4020 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4021 xmlXPathFreeObject(arg);
4022 xmlXPathFreeObject(s);
4023 return(0);
4024 }
4025 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004026 if (ns != NULL) {
4027 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004028 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004029 if (str2 != NULL) {
4030 valuePush(ctxt,
4031 xmlXPathNewString(str2));
4032 xmlFree(str2);
4033 valuePush(ctxt, xmlXPathObjectCopy(s));
4034 ret = xmlXPathCompareValues(ctxt, inf, strict);
4035 if (ret)
4036 break;
4037 }
4038 }
Owen Taylor3473f882001-02-23 17:55:21 +00004039 }
4040 xmlXPathFreeObject(arg);
4041 xmlXPathFreeObject(s);
4042 return(ret);
4043}
4044
4045/**
4046 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004047 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00004048 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004049 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00004050 * @arg2: the second node set object
4051 *
4052 * Implement the compare operation on nodesets:
4053 *
4054 * If both objects to be compared are node-sets, then the comparison
4055 * will be true if and only if there is a node in the first node-set
4056 * and a node in the second node-set such that the result of performing
4057 * the comparison on the string-values of the two nodes is true.
4058 * ....
4059 * When neither object to be compared is a node-set and the operator
4060 * is <=, <, >= or >, then the objects are compared by converting both
4061 * objects to numbers and comparing the numbers according to IEEE 754.
4062 * ....
4063 * The number function converts its argument to a number as follows:
4064 * - a string that consists of optional whitespace followed by an
4065 * optional minus sign followed by a Number followed by whitespace
4066 * is converted to the IEEE 754 number that is nearest (according
4067 * to the IEEE 754 round-to-nearest rule) to the mathematical value
4068 * represented by the string; any other string is converted to NaN
4069 *
4070 * Conclusion all nodes need to be converted first to their string value
4071 * and then the comparison must be done when possible
4072 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004073static int
4074xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00004075 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4076 int i, j, init = 0;
4077 double val1;
4078 double *values2;
4079 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004080 xmlNodeSetPtr ns1;
4081 xmlNodeSetPtr ns2;
4082
4083 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004084 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4085 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004086 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004087 }
Owen Taylor3473f882001-02-23 17:55:21 +00004088 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004089 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4090 xmlXPathFreeObject(arg1);
4091 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004092 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004093 }
Owen Taylor3473f882001-02-23 17:55:21 +00004094
4095 ns1 = arg1->nodesetval;
4096 ns2 = arg2->nodesetval;
4097
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004098 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004099 xmlXPathFreeObject(arg1);
4100 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004101 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004102 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004103 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004104 xmlXPathFreeObject(arg1);
4105 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004106 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004107 }
Owen Taylor3473f882001-02-23 17:55:21 +00004108
4109 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4110 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004111 xmlXPathFreeObject(arg1);
4112 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004113 return(0);
4114 }
4115 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004116 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004117 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004118 continue;
4119 for (j = 0;j < ns2->nodeNr;j++) {
4120 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004121 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004122 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004123 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004124 continue;
4125 if (inf && strict)
4126 ret = (val1 < values2[j]);
4127 else if (inf && !strict)
4128 ret = (val1 <= values2[j]);
4129 else if (!inf && strict)
4130 ret = (val1 > values2[j]);
4131 else if (!inf && !strict)
4132 ret = (val1 >= values2[j]);
4133 if (ret)
4134 break;
4135 }
4136 if (ret)
4137 break;
4138 init = 1;
4139 }
4140 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004141 xmlXPathFreeObject(arg1);
4142 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004143 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004144}
4145
4146/**
4147 * xmlXPathCompareNodeSetValue:
4148 * @ctxt: the XPath Parser context
4149 * @inf: less than (1) or greater than (0)
4150 * @strict: is the comparison strict
4151 * @arg: the node set
4152 * @val: the value
4153 *
4154 * Implement the compare operation between a nodeset and a value
4155 * @ns < @val (1, 1, ...
4156 * @ns <= @val (1, 0, ...
4157 * @ns > @val (0, 1, ...
4158 * @ns >= @val (0, 0, ...
4159 *
4160 * If one object to be compared is a node-set and the other is a boolean,
4161 * then the comparison will be true if and only if the result of performing
4162 * the comparison on the boolean and on the result of converting
4163 * the node-set to a boolean using the boolean function is true.
4164 *
4165 * Returns 0 or 1 depending on the results of the test.
4166 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004167static int
Owen Taylor3473f882001-02-23 17:55:21 +00004168xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4169 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4170 if ((val == NULL) || (arg == NULL) ||
4171 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4172 return(0);
4173
4174 switch(val->type) {
4175 case XPATH_NUMBER:
4176 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4177 case XPATH_NODESET:
4178 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004179 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004180 case XPATH_STRING:
4181 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4182 case XPATH_BOOLEAN:
4183 valuePush(ctxt, arg);
4184 xmlXPathBooleanFunction(ctxt, 1);
4185 valuePush(ctxt, val);
4186 return(xmlXPathCompareValues(ctxt, inf, strict));
4187 default:
4188 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004189 }
4190 return(0);
4191}
4192
4193/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004194 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00004195 * @arg: the nodeset object argument
4196 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00004197 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004198 *
4199 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4200 * If one object to be compared is a node-set and the other is a string,
4201 * then the comparison will be true if and only if there is a node in
4202 * the node-set such that the result of performing the comparison on the
4203 * string-value of the node and the other string is true.
4204 *
4205 * Returns 0 or 1 depending on the results of the test.
4206 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004207static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004208xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004209{
Owen Taylor3473f882001-02-23 17:55:21 +00004210 int i;
4211 xmlNodeSetPtr ns;
4212 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004213 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004214
4215 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004216 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4217 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004218 ns = arg->nodesetval;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004219 hash = xmlXPathStringHash(str);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004220 if (ns == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004221 return (0);
Daniel Veillard73c9c042001-07-05 20:02:54 +00004222 if (ns->nodeNr <= 0) {
4223 if (hash == 0)
William M. Brack0c022ad2002-07-12 00:56:01 +00004224 return(neq ^ 1);
4225 return(neq);
Daniel Veillard73c9c042001-07-05 20:02:54 +00004226 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004227 for (i = 0; i < ns->nodeNr; i++) {
4228 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4229 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4230 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4231 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004232 if (neq)
4233 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004234 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00004235 } else if (neq) {
4236 if (str2 != NULL)
4237 xmlFree(str2);
4238 return (1);
4239 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004240 if (str2 != NULL)
4241 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004242 } else if (neq)
4243 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00004244 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004245 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004246}
4247
4248/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004249 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00004250 * @arg: the nodeset object argument
4251 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00004252 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004253 *
4254 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4255 * If one object to be compared is a node-set and the other is a number,
4256 * then the comparison will be true if and only if there is a node in
4257 * the node-set such that the result of performing the comparison on the
4258 * number to be compared and on the result of converting the string-value
4259 * of that node to a number using the number function is true.
4260 *
4261 * Returns 0 or 1 depending on the results of the test.
4262 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004263static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004264xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
4265 xmlXPathObjectPtr arg, double f, int neq) {
4266 int i, ret=0;
4267 xmlNodeSetPtr ns;
4268 xmlChar *str2;
4269 xmlXPathObjectPtr val;
4270 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00004271
4272 if ((arg == NULL) ||
4273 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4274 return(0);
4275
William M. Brack0c022ad2002-07-12 00:56:01 +00004276 ns = arg->nodesetval;
4277 if (ns != NULL) {
4278 for (i=0;i<ns->nodeNr;i++) {
4279 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4280 if (str2 != NULL) {
4281 valuePush(ctxt, xmlXPathNewString(str2));
4282 xmlFree(str2);
4283 xmlXPathNumberFunction(ctxt, 1);
4284 val = valuePop(ctxt);
4285 v = val->floatval;
4286 xmlXPathFreeObject(val);
4287 if (!xmlXPathIsNaN(v)) {
4288 if ((!neq) && (v==f)) {
4289 ret = 1;
4290 break;
4291 } else if ((neq) && (v!=f)) {
4292 ret = 1;
4293 break;
4294 }
4295 }
4296 }
4297 }
4298 }
4299
4300 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004301}
4302
4303
4304/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004305 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00004306 * @arg1: first nodeset object argument
4307 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00004308 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004309 *
William M. Brack0c022ad2002-07-12 00:56:01 +00004310 * Implement the equal / not equal operation on XPath nodesets:
4311 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00004312 * If both objects to be compared are node-sets, then the comparison
4313 * will be true if and only if there is a node in the first node-set and
4314 * a node in the second node-set such that the result of performing the
4315 * comparison on the string-values of the two nodes is true.
4316 *
4317 * (needless to say, this is a costly operation)
4318 *
4319 * Returns 0 or 1 depending on the results of the test.
4320 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004321static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004322xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00004323 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004324 unsigned int *hashs1;
4325 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004326 xmlChar **values1;
4327 xmlChar **values2;
4328 int ret = 0;
4329 xmlNodeSetPtr ns1;
4330 xmlNodeSetPtr ns2;
4331
4332 if ((arg1 == NULL) ||
4333 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4334 return(0);
4335 if ((arg2 == NULL) ||
4336 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4337 return(0);
4338
4339 ns1 = arg1->nodesetval;
4340 ns2 = arg2->nodesetval;
4341
Daniel Veillard911f49a2001-04-07 15:39:35 +00004342 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004343 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004344 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004345 return(0);
4346
4347 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00004348 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00004349 */
William M. Brack0c022ad2002-07-12 00:56:01 +00004350 if (neq == 0)
4351 for (i = 0;i < ns1->nodeNr;i++)
4352 for (j = 0;j < ns2->nodeNr;j++)
4353 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4354 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00004355
4356 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
4357 if (values1 == NULL)
4358 return(0);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004359 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4360 if (hashs1 == NULL) {
4361 xmlFree(values1);
4362 return(0);
4363 }
Owen Taylor3473f882001-02-23 17:55:21 +00004364 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4365 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4366 if (values2 == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004367 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004368 xmlFree(values1);
4369 return(0);
4370 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004371 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4372 if (hashs2 == NULL) {
4373 xmlFree(hashs1);
4374 xmlFree(values1);
4375 xmlFree(values2);
4376 return(0);
4377 }
Owen Taylor3473f882001-02-23 17:55:21 +00004378 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4379 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004380 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004381 for (j = 0;j < ns2->nodeNr;j++) {
4382 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004383 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004384 if (hashs1[i] != hashs2[j]) {
4385 if (neq) {
4386 ret = 1;
4387 break;
4388 }
4389 }
4390 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004391 if (values1[i] == NULL)
4392 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4393 if (values2[j] == NULL)
4394 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004395 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004396 if (ret)
4397 break;
4398 }
Owen Taylor3473f882001-02-23 17:55:21 +00004399 }
4400 if (ret)
4401 break;
4402 }
4403 for (i = 0;i < ns1->nodeNr;i++)
4404 if (values1[i] != NULL)
4405 xmlFree(values1[i]);
4406 for (j = 0;j < ns2->nodeNr;j++)
4407 if (values2[j] != NULL)
4408 xmlFree(values2[j]);
4409 xmlFree(values1);
4410 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004411 xmlFree(hashs1);
4412 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004413 return(ret);
4414}
4415
William M. Brack0c022ad2002-07-12 00:56:01 +00004416static int
4417xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
4418 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00004419 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00004420 /*
4421 *At this point we are assured neither arg1 nor arg2
4422 *is a nodeset, so we can just pick the appropriate routine.
4423 */
Owen Taylor3473f882001-02-23 17:55:21 +00004424 switch (arg1->type) {
4425 case XPATH_UNDEFINED:
4426#ifdef DEBUG_EXPR
4427 xmlGenericError(xmlGenericErrorContext,
4428 "Equal: undefined\n");
4429#endif
4430 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004431 case XPATH_BOOLEAN:
4432 switch (arg2->type) {
4433 case XPATH_UNDEFINED:
4434#ifdef DEBUG_EXPR
4435 xmlGenericError(xmlGenericErrorContext,
4436 "Equal: undefined\n");
4437#endif
4438 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004439 case XPATH_BOOLEAN:
4440#ifdef DEBUG_EXPR
4441 xmlGenericError(xmlGenericErrorContext,
4442 "Equal: %d boolean %d \n",
4443 arg1->boolval, arg2->boolval);
4444#endif
4445 ret = (arg1->boolval == arg2->boolval);
4446 break;
4447 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00004448 ret = (arg1->boolval ==
4449 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004450 break;
4451 case XPATH_STRING:
4452 if ((arg2->stringval == NULL) ||
4453 (arg2->stringval[0] == 0)) ret = 0;
4454 else
4455 ret = 1;
4456 ret = (arg1->boolval == ret);
4457 break;
4458 case XPATH_USERS:
4459 case XPATH_POINT:
4460 case XPATH_RANGE:
4461 case XPATH_LOCATIONSET:
4462 TODO
4463 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004464 case XPATH_NODESET:
4465 case XPATH_XSLT_TREE:
4466 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004467 }
4468 break;
4469 case XPATH_NUMBER:
4470 switch (arg2->type) {
4471 case XPATH_UNDEFINED:
4472#ifdef DEBUG_EXPR
4473 xmlGenericError(xmlGenericErrorContext,
4474 "Equal: undefined\n");
4475#endif
4476 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004477 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00004478 ret = (arg2->boolval==
4479 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004480 break;
4481 case XPATH_STRING:
4482 valuePush(ctxt, arg2);
4483 xmlXPathNumberFunction(ctxt, 1);
4484 arg2 = valuePop(ctxt);
4485 /* no break on purpose */
4486 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004487 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004488 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4489 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004490 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4491 if (xmlXPathIsInf(arg2->floatval) == 1)
4492 ret = 1;
4493 else
4494 ret = 0;
4495 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4496 if (xmlXPathIsInf(arg2->floatval) == -1)
4497 ret = 1;
4498 else
4499 ret = 0;
4500 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4501 if (xmlXPathIsInf(arg1->floatval) == 1)
4502 ret = 1;
4503 else
4504 ret = 0;
4505 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4506 if (xmlXPathIsInf(arg1->floatval) == -1)
4507 ret = 1;
4508 else
4509 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004510 } else {
4511 ret = (arg1->floatval == arg2->floatval);
4512 }
Owen Taylor3473f882001-02-23 17:55:21 +00004513 break;
4514 case XPATH_USERS:
4515 case XPATH_POINT:
4516 case XPATH_RANGE:
4517 case XPATH_LOCATIONSET:
4518 TODO
4519 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004520 case XPATH_NODESET:
4521 case XPATH_XSLT_TREE:
4522 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004523 }
4524 break;
4525 case XPATH_STRING:
4526 switch (arg2->type) {
4527 case XPATH_UNDEFINED:
4528#ifdef DEBUG_EXPR
4529 xmlGenericError(xmlGenericErrorContext,
4530 "Equal: undefined\n");
4531#endif
4532 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004533 case XPATH_BOOLEAN:
4534 if ((arg1->stringval == NULL) ||
4535 (arg1->stringval[0] == 0)) ret = 0;
4536 else
4537 ret = 1;
4538 ret = (arg2->boolval == ret);
4539 break;
4540 case XPATH_STRING:
4541 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4542 break;
4543 case XPATH_NUMBER:
4544 valuePush(ctxt, arg1);
4545 xmlXPathNumberFunction(ctxt, 1);
4546 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004547 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004548 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4549 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004550 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4551 if (xmlXPathIsInf(arg2->floatval) == 1)
4552 ret = 1;
4553 else
4554 ret = 0;
4555 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4556 if (xmlXPathIsInf(arg2->floatval) == -1)
4557 ret = 1;
4558 else
4559 ret = 0;
4560 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4561 if (xmlXPathIsInf(arg1->floatval) == 1)
4562 ret = 1;
4563 else
4564 ret = 0;
4565 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4566 if (xmlXPathIsInf(arg1->floatval) == -1)
4567 ret = 1;
4568 else
4569 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004570 } else {
4571 ret = (arg1->floatval == arg2->floatval);
4572 }
Owen Taylor3473f882001-02-23 17:55:21 +00004573 break;
4574 case XPATH_USERS:
4575 case XPATH_POINT:
4576 case XPATH_RANGE:
4577 case XPATH_LOCATIONSET:
4578 TODO
4579 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004580 case XPATH_NODESET:
4581 case XPATH_XSLT_TREE:
4582 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004583 }
4584 break;
4585 case XPATH_USERS:
4586 case XPATH_POINT:
4587 case XPATH_RANGE:
4588 case XPATH_LOCATIONSET:
4589 TODO
4590 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004591 case XPATH_NODESET:
4592 case XPATH_XSLT_TREE:
4593 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004594 }
4595 xmlXPathFreeObject(arg1);
4596 xmlXPathFreeObject(arg2);
4597 return(ret);
4598}
4599
William M. Brack0c022ad2002-07-12 00:56:01 +00004600/**
4601 * xmlXPathEqualValues:
4602 * @ctxt: the XPath Parser context
4603 *
4604 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4605 *
4606 * Returns 0 or 1 depending on the results of the test.
4607 */
4608int
4609xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4610 xmlXPathObjectPtr arg1, arg2, argtmp;
4611 int ret = 0;
4612
4613 arg2 = valuePop(ctxt);
4614 arg1 = valuePop(ctxt);
4615 if ((arg1 == NULL) || (arg2 == NULL)) {
4616 if (arg1 != NULL)
4617 xmlXPathFreeObject(arg1);
4618 else
4619 xmlXPathFreeObject(arg2);
4620 XP_ERROR0(XPATH_INVALID_OPERAND);
4621 }
4622
4623 if (arg1 == arg2) {
4624#ifdef DEBUG_EXPR
4625 xmlGenericError(xmlGenericErrorContext,
4626 "Equal: by pointer\n");
4627#endif
4628 return(1);
4629 }
4630
4631 /*
4632 *If either argument is a nodeset, it's a 'special case'
4633 */
4634 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4635 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4636 /*
4637 *Hack it to assure arg1 is the nodeset
4638 */
4639 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4640 argtmp = arg2;
4641 arg2 = arg1;
4642 arg1 = argtmp;
4643 }
4644 switch (arg2->type) {
4645 case XPATH_UNDEFINED:
4646#ifdef DEBUG_EXPR
4647 xmlGenericError(xmlGenericErrorContext,
4648 "Equal: undefined\n");
4649#endif
4650 break;
4651 case XPATH_NODESET:
4652 case XPATH_XSLT_TREE:
4653 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
4654 break;
4655 case XPATH_BOOLEAN:
4656 if ((arg1->nodesetval == NULL) ||
4657 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4658 else
4659 ret = 1;
4660 ret = (ret == arg2->boolval);
4661 break;
4662 case XPATH_NUMBER:
4663 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
4664 break;
4665 case XPATH_STRING:
4666 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
4667 break;
4668 case XPATH_USERS:
4669 case XPATH_POINT:
4670 case XPATH_RANGE:
4671 case XPATH_LOCATIONSET:
4672 TODO
4673 break;
4674 }
4675 xmlXPathFreeObject(arg1);
4676 xmlXPathFreeObject(arg2);
4677 return(ret);
4678 }
4679
4680 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4681}
4682
4683/**
4684 * xmlXPathNotEqualValues:
4685 * @ctxt: the XPath Parser context
4686 *
4687 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4688 *
4689 * Returns 0 or 1 depending on the results of the test.
4690 */
4691int
4692xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
4693 xmlXPathObjectPtr arg1, arg2, argtmp;
4694 int ret = 0;
4695
4696 arg2 = valuePop(ctxt);
4697 arg1 = valuePop(ctxt);
4698 if ((arg1 == NULL) || (arg2 == NULL)) {
4699 if (arg1 != NULL)
4700 xmlXPathFreeObject(arg1);
4701 else
4702 xmlXPathFreeObject(arg2);
4703 XP_ERROR0(XPATH_INVALID_OPERAND);
4704 }
4705
4706 if (arg1 == arg2) {
4707#ifdef DEBUG_EXPR
4708 xmlGenericError(xmlGenericErrorContext,
4709 "NotEqual: by pointer\n");
4710#endif
4711 return(0);
4712 }
4713
4714 /*
4715 *If either argument is a nodeset, it's a 'special case'
4716 */
4717 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4718 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4719 /*
4720 *Hack it to assure arg1 is the nodeset
4721 */
4722 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4723 argtmp = arg2;
4724 arg2 = arg1;
4725 arg1 = argtmp;
4726 }
4727 switch (arg2->type) {
4728 case XPATH_UNDEFINED:
4729#ifdef DEBUG_EXPR
4730 xmlGenericError(xmlGenericErrorContext,
4731 "NotEqual: undefined\n");
4732#endif
4733 break;
4734 case XPATH_NODESET:
4735 case XPATH_XSLT_TREE:
4736 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
4737 break;
4738 case XPATH_BOOLEAN:
4739 if ((arg1->nodesetval == NULL) ||
4740 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4741 else
4742 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00004743 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00004744 break;
4745 case XPATH_NUMBER:
4746 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
4747 break;
4748 case XPATH_STRING:
4749 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
4750 break;
4751 case XPATH_USERS:
4752 case XPATH_POINT:
4753 case XPATH_RANGE:
4754 case XPATH_LOCATIONSET:
4755 TODO
4756 break;
4757 }
4758 xmlXPathFreeObject(arg1);
4759 xmlXPathFreeObject(arg2);
4760 return(ret);
4761 }
4762
4763 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4764}
Owen Taylor3473f882001-02-23 17:55:21 +00004765
4766/**
4767 * xmlXPathCompareValues:
4768 * @ctxt: the XPath Parser context
4769 * @inf: less than (1) or greater than (0)
4770 * @strict: is the comparison strict
4771 *
4772 * Implement the compare operation on XPath objects:
4773 * @arg1 < @arg2 (1, 1, ...
4774 * @arg1 <= @arg2 (1, 0, ...
4775 * @arg1 > @arg2 (0, 1, ...
4776 * @arg1 >= @arg2 (0, 0, ...
4777 *
4778 * When neither object to be compared is a node-set and the operator is
4779 * <=, <, >=, >, then the objects are compared by converted both objects
4780 * to numbers and comparing the numbers according to IEEE 754. The <
4781 * comparison will be true if and only if the first number is less than the
4782 * second number. The <= comparison will be true if and only if the first
4783 * number is less than or equal to the second number. The > comparison
4784 * will be true if and only if the first number is greater than the second
4785 * number. The >= comparison will be true if and only if the first number
4786 * is greater than or equal to the second number.
4787 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004788 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00004789 */
4790int
4791xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004792 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004793 xmlXPathObjectPtr arg1, arg2;
4794
William M. Brack0c022ad2002-07-12 00:56:01 +00004795 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00004796 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00004797 if ((arg1 == NULL) || (arg2 == NULL)) {
4798 if (arg1 != NULL)
4799 xmlXPathFreeObject(arg1);
4800 else
4801 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004802 XP_ERROR0(XPATH_INVALID_OPERAND);
4803 }
4804
William M. Brack0c022ad2002-07-12 00:56:01 +00004805 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4806 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4807 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
4808 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004809 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004810 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00004811 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004812 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
4813 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004814 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004815 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
4816 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00004817 }
4818 }
4819 return(ret);
4820 }
4821
4822 if (arg1->type != XPATH_NUMBER) {
4823 valuePush(ctxt, arg1);
4824 xmlXPathNumberFunction(ctxt, 1);
4825 arg1 = valuePop(ctxt);
4826 }
4827 if (arg1->type != XPATH_NUMBER) {
4828 xmlXPathFreeObject(arg1);
4829 xmlXPathFreeObject(arg2);
4830 XP_ERROR0(XPATH_INVALID_OPERAND);
4831 }
4832 if (arg2->type != XPATH_NUMBER) {
4833 valuePush(ctxt, arg2);
4834 xmlXPathNumberFunction(ctxt, 1);
4835 arg2 = valuePop(ctxt);
4836 }
4837 if (arg2->type != XPATH_NUMBER) {
4838 xmlXPathFreeObject(arg1);
4839 xmlXPathFreeObject(arg2);
4840 XP_ERROR0(XPATH_INVALID_OPERAND);
4841 }
4842 /*
4843 * Add tests for infinity and nan
4844 * => feedback on 3.4 for Inf and NaN
4845 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004846 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00004847 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004848 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004849 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004850 arg1i=xmlXPathIsInf(arg1->floatval);
4851 arg2i=xmlXPathIsInf(arg2->floatval);
4852 if (inf && strict) {
4853 if ((arg1i == -1 && arg2i != -1) ||
4854 (arg2i == 1 && arg1i != 1)) {
4855 ret = 1;
4856 } else if (arg1i == 0 && arg2i == 0) {
4857 ret = (arg1->floatval < arg2->floatval);
4858 } else {
4859 ret = 0;
4860 }
4861 }
4862 else if (inf && !strict) {
4863 if (arg1i == -1 || arg2i == 1) {
4864 ret = 1;
4865 } else if (arg1i == 0 && arg2i == 0) {
4866 ret = (arg1->floatval <= arg2->floatval);
4867 } else {
4868 ret = 0;
4869 }
4870 }
4871 else if (!inf && strict) {
4872 if ((arg1i == 1 && arg2i != 1) ||
4873 (arg2i == -1 && arg1i != -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 ret = 1;
4884 } else if (arg1i == 0 && arg2i == 0) {
4885 ret = (arg1->floatval >= arg2->floatval);
4886 } else {
4887 ret = 0;
4888 }
4889 }
Daniel Veillard21458c82002-03-27 16:12:22 +00004890 }
Owen Taylor3473f882001-02-23 17:55:21 +00004891 xmlXPathFreeObject(arg1);
4892 xmlXPathFreeObject(arg2);
4893 return(ret);
4894}
4895
4896/**
4897 * xmlXPathValueFlipSign:
4898 * @ctxt: the XPath Parser context
4899 *
4900 * Implement the unary - operation on an XPath object
4901 * The numeric operators convert their operands to numbers as if
4902 * by calling the number function.
4903 */
4904void
4905xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004906 CAST_TO_NUMBER;
4907 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00004908 if (xmlXPathIsNaN(ctxt->value->floatval))
4909 ctxt->value->floatval=xmlXPathNAN;
4910 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
4911 ctxt->value->floatval=xmlXPathNINF;
4912 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
4913 ctxt->value->floatval=xmlXPathPINF;
4914 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00004915 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
4916 ctxt->value->floatval = xmlXPathNZERO;
4917 else
4918 ctxt->value->floatval = 0;
4919 }
4920 else
4921 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00004922}
4923
4924/**
4925 * xmlXPathAddValues:
4926 * @ctxt: the XPath Parser context
4927 *
4928 * Implement the add operation on XPath objects:
4929 * The numeric operators convert their operands to numbers as if
4930 * by calling the number function.
4931 */
4932void
4933xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
4934 xmlXPathObjectPtr arg;
4935 double val;
4936
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004937 arg = valuePop(ctxt);
4938 if (arg == NULL)
4939 XP_ERROR(XPATH_INVALID_OPERAND);
4940 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004941 xmlXPathFreeObject(arg);
4942
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004943 CAST_TO_NUMBER;
4944 CHECK_TYPE(XPATH_NUMBER);
4945 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00004946}
4947
4948/**
4949 * xmlXPathSubValues:
4950 * @ctxt: the XPath Parser context
4951 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004952 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00004953 * The numeric operators convert their operands to numbers as if
4954 * by calling the number function.
4955 */
4956void
4957xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
4958 xmlXPathObjectPtr arg;
4959 double val;
4960
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004961 arg = valuePop(ctxt);
4962 if (arg == NULL)
4963 XP_ERROR(XPATH_INVALID_OPERAND);
4964 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004965 xmlXPathFreeObject(arg);
4966
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004967 CAST_TO_NUMBER;
4968 CHECK_TYPE(XPATH_NUMBER);
4969 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004970}
4971
4972/**
4973 * xmlXPathMultValues:
4974 * @ctxt: the XPath Parser context
4975 *
4976 * Implement the multiply operation on XPath objects:
4977 * The numeric operators convert their operands to numbers as if
4978 * by calling the number function.
4979 */
4980void
4981xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
4982 xmlXPathObjectPtr arg;
4983 double val;
4984
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004985 arg = valuePop(ctxt);
4986 if (arg == NULL)
4987 XP_ERROR(XPATH_INVALID_OPERAND);
4988 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004989 xmlXPathFreeObject(arg);
4990
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004991 CAST_TO_NUMBER;
4992 CHECK_TYPE(XPATH_NUMBER);
4993 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004994}
4995
4996/**
4997 * xmlXPathDivValues:
4998 * @ctxt: the XPath Parser context
4999 *
5000 * Implement the div operation on XPath objects @arg1 / @arg2:
5001 * The numeric operators convert their operands to numbers as if
5002 * by calling the number function.
5003 */
5004void
5005xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
5006 xmlXPathObjectPtr arg;
5007 double val;
5008
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005009 arg = valuePop(ctxt);
5010 if (arg == NULL)
5011 XP_ERROR(XPATH_INVALID_OPERAND);
5012 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005013 xmlXPathFreeObject(arg);
5014
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005015 CAST_TO_NUMBER;
5016 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005017 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
5018 ctxt->value->floatval = xmlXPathNAN;
5019 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005020 if (ctxt->value->floatval == 0)
5021 ctxt->value->floatval = xmlXPathNAN;
5022 else if (ctxt->value->floatval > 0)
5023 ctxt->value->floatval = xmlXPathNINF;
5024 else if (ctxt->value->floatval < 0)
5025 ctxt->value->floatval = xmlXPathPINF;
5026 }
5027 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00005028 if (ctxt->value->floatval == 0)
5029 ctxt->value->floatval = xmlXPathNAN;
5030 else if (ctxt->value->floatval > 0)
5031 ctxt->value->floatval = xmlXPathPINF;
5032 else if (ctxt->value->floatval < 0)
5033 ctxt->value->floatval = xmlXPathNINF;
5034 } else
5035 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005036}
5037
5038/**
5039 * xmlXPathModValues:
5040 * @ctxt: the XPath Parser context
5041 *
5042 * Implement the mod operation on XPath objects: @arg1 / @arg2
5043 * The numeric operators convert their operands to numbers as if
5044 * by calling the number function.
5045 */
5046void
5047xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
5048 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005049 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00005050
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005051 arg = valuePop(ctxt);
5052 if (arg == NULL)
5053 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005054 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005055 xmlXPathFreeObject(arg);
5056
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005057 CAST_TO_NUMBER;
5058 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005059 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00005060 if (arg2 == 0)
5061 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005062 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00005063 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005064 }
Owen Taylor3473f882001-02-23 17:55:21 +00005065}
5066
5067/************************************************************************
5068 * *
5069 * The traversal functions *
5070 * *
5071 ************************************************************************/
5072
Owen Taylor3473f882001-02-23 17:55:21 +00005073/*
5074 * A traversal function enumerates nodes along an axis.
5075 * Initially it must be called with NULL, and it indicates
5076 * termination on the axis by returning NULL.
5077 */
5078typedef xmlNodePtr (*xmlXPathTraversalFunction)
5079 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
5080
5081/**
5082 * xmlXPathNextSelf:
5083 * @ctxt: the XPath Parser context
5084 * @cur: the current node in the traversal
5085 *
5086 * Traversal function for the "self" direction
5087 * The self axis contains just the context node itself
5088 *
5089 * Returns the next element following that axis
5090 */
5091xmlNodePtr
5092xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5093 if (cur == NULL)
5094 return(ctxt->context->node);
5095 return(NULL);
5096}
5097
5098/**
5099 * xmlXPathNextChild:
5100 * @ctxt: the XPath Parser context
5101 * @cur: the current node in the traversal
5102 *
5103 * Traversal function for the "child" direction
5104 * The child axis contains the children of the context node in document order.
5105 *
5106 * Returns the next element following that axis
5107 */
5108xmlNodePtr
5109xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5110 if (cur == NULL) {
5111 if (ctxt->context->node == NULL) return(NULL);
5112 switch (ctxt->context->node->type) {
5113 case XML_ELEMENT_NODE:
5114 case XML_TEXT_NODE:
5115 case XML_CDATA_SECTION_NODE:
5116 case XML_ENTITY_REF_NODE:
5117 case XML_ENTITY_NODE:
5118 case XML_PI_NODE:
5119 case XML_COMMENT_NODE:
5120 case XML_NOTATION_NODE:
5121 case XML_DTD_NODE:
5122 return(ctxt->context->node->children);
5123 case XML_DOCUMENT_NODE:
5124 case XML_DOCUMENT_TYPE_NODE:
5125 case XML_DOCUMENT_FRAG_NODE:
5126 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005127#ifdef LIBXML_DOCB_ENABLED
5128 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005129#endif
5130 return(((xmlDocPtr) ctxt->context->node)->children);
5131 case XML_ELEMENT_DECL:
5132 case XML_ATTRIBUTE_DECL:
5133 case XML_ENTITY_DECL:
5134 case XML_ATTRIBUTE_NODE:
5135 case XML_NAMESPACE_DECL:
5136 case XML_XINCLUDE_START:
5137 case XML_XINCLUDE_END:
5138 return(NULL);
5139 }
5140 return(NULL);
5141 }
5142 if ((cur->type == XML_DOCUMENT_NODE) ||
5143 (cur->type == XML_HTML_DOCUMENT_NODE))
5144 return(NULL);
5145 return(cur->next);
5146}
5147
5148/**
5149 * xmlXPathNextDescendant:
5150 * @ctxt: the XPath Parser context
5151 * @cur: the current node in the traversal
5152 *
5153 * Traversal function for the "descendant" direction
5154 * the descendant axis contains the descendants of the context node in document
5155 * order; a descendant is a child or a child of a child and so on.
5156 *
5157 * Returns the next element following that axis
5158 */
5159xmlNodePtr
5160xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5161 if (cur == NULL) {
5162 if (ctxt->context->node == NULL)
5163 return(NULL);
5164 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5165 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5166 return(NULL);
5167
5168 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5169 return(ctxt->context->doc->children);
5170 return(ctxt->context->node->children);
5171 }
5172
Daniel Veillard567e1b42001-08-01 15:53:47 +00005173 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00005174 /*
5175 * Do not descend on entities declarations
5176 */
5177 if (cur->children->type != XML_ENTITY_DECL) {
5178 cur = cur->children;
5179 /*
5180 * Skip DTDs
5181 */
5182 if (cur->type != XML_DTD_NODE)
5183 return(cur);
5184 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00005185 }
5186
5187 if (cur == ctxt->context->node) return(NULL);
5188
Daniel Veillard68e9e742002-11-16 15:35:11 +00005189 while (cur->next != NULL) {
5190 cur = cur->next;
5191 if ((cur->type != XML_ENTITY_DECL) &&
5192 (cur->type != XML_DTD_NODE))
5193 return(cur);
5194 }
Owen Taylor3473f882001-02-23 17:55:21 +00005195
5196 do {
5197 cur = cur->parent;
5198 if (cur == NULL) return(NULL);
5199 if (cur == ctxt->context->node) return(NULL);
5200 if (cur->next != NULL) {
5201 cur = cur->next;
5202 return(cur);
5203 }
5204 } while (cur != NULL);
5205 return(cur);
5206}
5207
5208/**
5209 * xmlXPathNextDescendantOrSelf:
5210 * @ctxt: the XPath Parser context
5211 * @cur: the current node in the traversal
5212 *
5213 * Traversal function for the "descendant-or-self" direction
5214 * the descendant-or-self axis contains the context node and the descendants
5215 * of the context node in document order; thus the context node is the first
5216 * node on the axis, and the first child of the context node is the second node
5217 * on the axis
5218 *
5219 * Returns the next element following that axis
5220 */
5221xmlNodePtr
5222xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5223 if (cur == NULL) {
5224 if (ctxt->context->node == NULL)
5225 return(NULL);
5226 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5227 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5228 return(NULL);
5229 return(ctxt->context->node);
5230 }
5231
5232 return(xmlXPathNextDescendant(ctxt, cur));
5233}
5234
5235/**
5236 * xmlXPathNextParent:
5237 * @ctxt: the XPath Parser context
5238 * @cur: the current node in the traversal
5239 *
5240 * Traversal function for the "parent" direction
5241 * The parent axis contains the parent of the context node, if there is one.
5242 *
5243 * Returns the next element following that axis
5244 */
5245xmlNodePtr
5246xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5247 /*
5248 * the parent of an attribute or namespace node is the element
5249 * to which the attribute or namespace node is attached
5250 * Namespace handling !!!
5251 */
5252 if (cur == NULL) {
5253 if (ctxt->context->node == NULL) return(NULL);
5254 switch (ctxt->context->node->type) {
5255 case XML_ELEMENT_NODE:
5256 case XML_TEXT_NODE:
5257 case XML_CDATA_SECTION_NODE:
5258 case XML_ENTITY_REF_NODE:
5259 case XML_ENTITY_NODE:
5260 case XML_PI_NODE:
5261 case XML_COMMENT_NODE:
5262 case XML_NOTATION_NODE:
5263 case XML_DTD_NODE:
5264 case XML_ELEMENT_DECL:
5265 case XML_ATTRIBUTE_DECL:
5266 case XML_XINCLUDE_START:
5267 case XML_XINCLUDE_END:
5268 case XML_ENTITY_DECL:
5269 if (ctxt->context->node->parent == NULL)
5270 return((xmlNodePtr) ctxt->context->doc);
5271 return(ctxt->context->node->parent);
5272 case XML_ATTRIBUTE_NODE: {
5273 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5274
5275 return(att->parent);
5276 }
5277 case XML_DOCUMENT_NODE:
5278 case XML_DOCUMENT_TYPE_NODE:
5279 case XML_DOCUMENT_FRAG_NODE:
5280 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005281#ifdef LIBXML_DOCB_ENABLED
5282 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005283#endif
5284 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005285 case XML_NAMESPACE_DECL: {
5286 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5287
5288 if ((ns->next != NULL) &&
5289 (ns->next->type != XML_NAMESPACE_DECL))
5290 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005291 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005292 }
Owen Taylor3473f882001-02-23 17:55:21 +00005293 }
5294 }
5295 return(NULL);
5296}
5297
5298/**
5299 * xmlXPathNextAncestor:
5300 * @ctxt: the XPath Parser context
5301 * @cur: the current node in the traversal
5302 *
5303 * Traversal function for the "ancestor" direction
5304 * the ancestor axis contains the ancestors of the context node; the ancestors
5305 * of the context node consist of the parent of context node and the parent's
5306 * parent and so on; the nodes are ordered in reverse document order; thus the
5307 * parent is the first node on the axis, and the parent's parent is the second
5308 * node on the axis
5309 *
5310 * Returns the next element following that axis
5311 */
5312xmlNodePtr
5313xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5314 /*
5315 * the parent of an attribute or namespace node is the element
5316 * to which the attribute or namespace node is attached
5317 * !!!!!!!!!!!!!
5318 */
5319 if (cur == NULL) {
5320 if (ctxt->context->node == NULL) return(NULL);
5321 switch (ctxt->context->node->type) {
5322 case XML_ELEMENT_NODE:
5323 case XML_TEXT_NODE:
5324 case XML_CDATA_SECTION_NODE:
5325 case XML_ENTITY_REF_NODE:
5326 case XML_ENTITY_NODE:
5327 case XML_PI_NODE:
5328 case XML_COMMENT_NODE:
5329 case XML_DTD_NODE:
5330 case XML_ELEMENT_DECL:
5331 case XML_ATTRIBUTE_DECL:
5332 case XML_ENTITY_DECL:
5333 case XML_NOTATION_NODE:
5334 case XML_XINCLUDE_START:
5335 case XML_XINCLUDE_END:
5336 if (ctxt->context->node->parent == NULL)
5337 return((xmlNodePtr) ctxt->context->doc);
5338 return(ctxt->context->node->parent);
5339 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005340 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005341
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005342 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005343 }
5344 case XML_DOCUMENT_NODE:
5345 case XML_DOCUMENT_TYPE_NODE:
5346 case XML_DOCUMENT_FRAG_NODE:
5347 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005348#ifdef LIBXML_DOCB_ENABLED
5349 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005350#endif
5351 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005352 case XML_NAMESPACE_DECL: {
5353 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5354
5355 if ((ns->next != NULL) &&
5356 (ns->next->type != XML_NAMESPACE_DECL))
5357 return((xmlNodePtr) ns->next);
5358 /* Bad, how did that namespace ended-up there ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005359 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005360 }
Owen Taylor3473f882001-02-23 17:55:21 +00005361 }
5362 return(NULL);
5363 }
5364 if (cur == ctxt->context->doc->children)
5365 return((xmlNodePtr) ctxt->context->doc);
5366 if (cur == (xmlNodePtr) ctxt->context->doc)
5367 return(NULL);
5368 switch (cur->type) {
5369 case XML_ELEMENT_NODE:
5370 case XML_TEXT_NODE:
5371 case XML_CDATA_SECTION_NODE:
5372 case XML_ENTITY_REF_NODE:
5373 case XML_ENTITY_NODE:
5374 case XML_PI_NODE:
5375 case XML_COMMENT_NODE:
5376 case XML_NOTATION_NODE:
5377 case XML_DTD_NODE:
5378 case XML_ELEMENT_DECL:
5379 case XML_ATTRIBUTE_DECL:
5380 case XML_ENTITY_DECL:
5381 case XML_XINCLUDE_START:
5382 case XML_XINCLUDE_END:
5383 return(cur->parent);
5384 case XML_ATTRIBUTE_NODE: {
5385 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5386
5387 return(att->parent);
5388 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005389 case XML_NAMESPACE_DECL: {
5390 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5391
5392 if ((ns->next != NULL) &&
5393 (ns->next->type != XML_NAMESPACE_DECL))
5394 return((xmlNodePtr) ns->next);
5395 /* Bad, how did that namespace ended-up there ? */
5396 return(NULL);
5397 }
Owen Taylor3473f882001-02-23 17:55:21 +00005398 case XML_DOCUMENT_NODE:
5399 case XML_DOCUMENT_TYPE_NODE:
5400 case XML_DOCUMENT_FRAG_NODE:
5401 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005402#ifdef LIBXML_DOCB_ENABLED
5403 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005404#endif
5405 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005406 }
5407 return(NULL);
5408}
5409
5410/**
5411 * xmlXPathNextAncestorOrSelf:
5412 * @ctxt: the XPath Parser context
5413 * @cur: the current node in the traversal
5414 *
5415 * Traversal function for the "ancestor-or-self" direction
5416 * he ancestor-or-self axis contains the context node and ancestors of
5417 * the context node in reverse document order; thus the context node is
5418 * the first node on the axis, and the context node's parent the second;
5419 * parent here is defined the same as with the parent axis.
5420 *
5421 * Returns the next element following that axis
5422 */
5423xmlNodePtr
5424xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5425 if (cur == NULL)
5426 return(ctxt->context->node);
5427 return(xmlXPathNextAncestor(ctxt, cur));
5428}
5429
5430/**
5431 * xmlXPathNextFollowingSibling:
5432 * @ctxt: the XPath Parser context
5433 * @cur: the current node in the traversal
5434 *
5435 * Traversal function for the "following-sibling" direction
5436 * The following-sibling axis contains the following siblings of the context
5437 * node in document order.
5438 *
5439 * Returns the next element following that axis
5440 */
5441xmlNodePtr
5442xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5443 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5444 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5445 return(NULL);
5446 if (cur == (xmlNodePtr) ctxt->context->doc)
5447 return(NULL);
5448 if (cur == NULL)
5449 return(ctxt->context->node->next);
5450 return(cur->next);
5451}
5452
5453/**
5454 * xmlXPathNextPrecedingSibling:
5455 * @ctxt: the XPath Parser context
5456 * @cur: the current node in the traversal
5457 *
5458 * Traversal function for the "preceding-sibling" direction
5459 * The preceding-sibling axis contains the preceding siblings of the context
5460 * node in reverse document order; the first preceding sibling is first on the
5461 * axis; the sibling preceding that node is the second on the axis and so on.
5462 *
5463 * Returns the next element following that axis
5464 */
5465xmlNodePtr
5466xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5467 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5468 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5469 return(NULL);
5470 if (cur == (xmlNodePtr) ctxt->context->doc)
5471 return(NULL);
5472 if (cur == NULL)
5473 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005474 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5475 cur = cur->prev;
5476 if (cur == NULL)
5477 return(ctxt->context->node->prev);
5478 }
Owen Taylor3473f882001-02-23 17:55:21 +00005479 return(cur->prev);
5480}
5481
5482/**
5483 * xmlXPathNextFollowing:
5484 * @ctxt: the XPath Parser context
5485 * @cur: the current node in the traversal
5486 *
5487 * Traversal function for the "following" direction
5488 * The following axis contains all nodes in the same document as the context
5489 * node that are after the context node in document order, excluding any
5490 * descendants and excluding attribute nodes and namespace nodes; the nodes
5491 * are ordered in document order
5492 *
5493 * Returns the next element following that axis
5494 */
5495xmlNodePtr
5496xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5497 if (cur != NULL && cur->children != NULL)
5498 return cur->children ;
5499 if (cur == NULL) cur = ctxt->context->node;
5500 if (cur == NULL) return(NULL) ; /* ERROR */
5501 if (cur->next != NULL) return(cur->next) ;
5502 do {
5503 cur = cur->parent;
5504 if (cur == NULL) return(NULL);
5505 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5506 if (cur->next != NULL) return(cur->next);
5507 } while (cur != NULL);
5508 return(cur);
5509}
5510
5511/*
5512 * xmlXPathIsAncestor:
5513 * @ancestor: the ancestor node
5514 * @node: the current node
5515 *
5516 * Check that @ancestor is a @node's ancestor
5517 *
5518 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5519 */
5520static int
5521xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5522 if ((ancestor == NULL) || (node == NULL)) return(0);
5523 /* nodes need to be in the same document */
5524 if (ancestor->doc != node->doc) return(0);
5525 /* avoid searching if ancestor or node is the root node */
5526 if (ancestor == (xmlNodePtr) node->doc) return(1);
5527 if (node == (xmlNodePtr) ancestor->doc) return(0);
5528 while (node->parent != NULL) {
5529 if (node->parent == ancestor)
5530 return(1);
5531 node = node->parent;
5532 }
5533 return(0);
5534}
5535
5536/**
5537 * xmlXPathNextPreceding:
5538 * @ctxt: the XPath Parser context
5539 * @cur: the current node in the traversal
5540 *
5541 * Traversal function for the "preceding" direction
5542 * the preceding axis contains all nodes in the same document as the context
5543 * node that are before the context node in document order, excluding any
5544 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5545 * ordered in reverse document order
5546 *
5547 * Returns the next element following that axis
5548 */
5549xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005550xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5551{
Owen Taylor3473f882001-02-23 17:55:21 +00005552 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005553 cur = ctxt->context->node;
5554 if (cur == NULL)
5555 return (NULL);
5556 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5557 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005558 do {
5559 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005560 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5561 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005562 }
5563
5564 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005565 if (cur == NULL)
5566 return (NULL);
5567 if (cur == ctxt->context->doc->children)
5568 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005569 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005570 return (cur);
5571}
5572
5573/**
5574 * xmlXPathNextPrecedingInternal:
5575 * @ctxt: the XPath Parser context
5576 * @cur: the current node in the traversal
5577 *
5578 * Traversal function for the "preceding" direction
5579 * the preceding axis contains all nodes in the same document as the context
5580 * node that are before the context node in document order, excluding any
5581 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5582 * ordered in reverse document order
5583 * This is a faster implementation but internal only since it requires a
5584 * state kept in the parser context: ctxt->ancestor.
5585 *
5586 * Returns the next element following that axis
5587 */
5588static xmlNodePtr
5589xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5590 xmlNodePtr cur)
5591{
5592 if (cur == NULL) {
5593 cur = ctxt->context->node;
5594 if (cur == NULL)
5595 return (NULL);
5596 ctxt->ancestor = cur->parent;
5597 }
5598 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5599 cur = cur->prev;
5600 while (cur->prev == NULL) {
5601 cur = cur->parent;
5602 if (cur == NULL)
5603 return (NULL);
5604 if (cur == ctxt->context->doc->children)
5605 return (NULL);
5606 if (cur != ctxt->ancestor)
5607 return (cur);
5608 ctxt->ancestor = cur->parent;
5609 }
5610 cur = cur->prev;
5611 while (cur->last != NULL)
5612 cur = cur->last;
5613 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005614}
5615
5616/**
5617 * xmlXPathNextNamespace:
5618 * @ctxt: the XPath Parser context
5619 * @cur: the current attribute in the traversal
5620 *
5621 * Traversal function for the "namespace" direction
5622 * the namespace axis contains the namespace nodes of the context node;
5623 * the order of nodes on this axis is implementation-defined; the axis will
5624 * be empty unless the context node is an element
5625 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005626 * We keep the XML namespace node at the end of the list.
5627 *
Owen Taylor3473f882001-02-23 17:55:21 +00005628 * Returns the next element following that axis
5629 */
5630xmlNodePtr
5631xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5632 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00005633 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005634 if (ctxt->context->tmpNsList != NULL)
5635 xmlFree(ctxt->context->tmpNsList);
5636 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005637 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005638 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005639 if (ctxt->context->tmpNsList != NULL) {
5640 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
5641 ctxt->context->tmpNsNr++;
5642 }
5643 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005644 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005645 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00005646 if (ctxt->context->tmpNsNr > 0) {
5647 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
5648 } else {
5649 if (ctxt->context->tmpNsList != NULL)
5650 xmlFree(ctxt->context->tmpNsList);
5651 ctxt->context->tmpNsList = NULL;
5652 return(NULL);
5653 }
Owen Taylor3473f882001-02-23 17:55:21 +00005654}
5655
5656/**
5657 * xmlXPathNextAttribute:
5658 * @ctxt: the XPath Parser context
5659 * @cur: the current attribute in the traversal
5660 *
5661 * Traversal function for the "attribute" direction
5662 * TODO: support DTD inherited default attributes
5663 *
5664 * Returns the next element following that axis
5665 */
5666xmlNodePtr
5667xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005668 if (ctxt->context->node == NULL)
5669 return(NULL);
5670 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5671 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005672 if (cur == NULL) {
5673 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5674 return(NULL);
5675 return((xmlNodePtr)ctxt->context->node->properties);
5676 }
5677 return((xmlNodePtr)cur->next);
5678}
5679
5680/************************************************************************
5681 * *
5682 * NodeTest Functions *
5683 * *
5684 ************************************************************************/
5685
Owen Taylor3473f882001-02-23 17:55:21 +00005686#define IS_FUNCTION 200
5687
Owen Taylor3473f882001-02-23 17:55:21 +00005688
5689/************************************************************************
5690 * *
5691 * Implicit tree core function library *
5692 * *
5693 ************************************************************************/
5694
5695/**
5696 * xmlXPathRoot:
5697 * @ctxt: the XPath Parser context
5698 *
5699 * Initialize the context to the root of the document
5700 */
5701void
5702xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5703 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5704 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5705}
5706
5707/************************************************************************
5708 * *
5709 * The explicit core function library *
5710 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5711 * *
5712 ************************************************************************/
5713
5714
5715/**
5716 * xmlXPathLastFunction:
5717 * @ctxt: the XPath Parser context
5718 * @nargs: the number of arguments
5719 *
5720 * Implement the last() XPath function
5721 * number last()
5722 * The last function returns the number of nodes in the context node list.
5723 */
5724void
5725xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5726 CHECK_ARITY(0);
5727 if (ctxt->context->contextSize >= 0) {
5728 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5729#ifdef DEBUG_EXPR
5730 xmlGenericError(xmlGenericErrorContext,
5731 "last() : %d\n", ctxt->context->contextSize);
5732#endif
5733 } else {
5734 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5735 }
5736}
5737
5738/**
5739 * xmlXPathPositionFunction:
5740 * @ctxt: the XPath Parser context
5741 * @nargs: the number of arguments
5742 *
5743 * Implement the position() XPath function
5744 * number position()
5745 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005746 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00005747 * will be equal to last().
5748 */
5749void
5750xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5751 CHECK_ARITY(0);
5752 if (ctxt->context->proximityPosition >= 0) {
5753 valuePush(ctxt,
5754 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5755#ifdef DEBUG_EXPR
5756 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5757 ctxt->context->proximityPosition);
5758#endif
5759 } else {
5760 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5761 }
5762}
5763
5764/**
5765 * xmlXPathCountFunction:
5766 * @ctxt: the XPath Parser context
5767 * @nargs: the number of arguments
5768 *
5769 * Implement the count() XPath function
5770 * number count(node-set)
5771 */
5772void
5773xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5774 xmlXPathObjectPtr cur;
5775
5776 CHECK_ARITY(1);
5777 if ((ctxt->value == NULL) ||
5778 ((ctxt->value->type != XPATH_NODESET) &&
5779 (ctxt->value->type != XPATH_XSLT_TREE)))
5780 XP_ERROR(XPATH_INVALID_TYPE);
5781 cur = valuePop(ctxt);
5782
Daniel Veillard911f49a2001-04-07 15:39:35 +00005783 if ((cur == NULL) || (cur->nodesetval == NULL))
5784 valuePush(ctxt, xmlXPathNewFloat((double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00005785 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00005786 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00005787 } else {
5788 if ((cur->nodesetval->nodeNr != 1) ||
5789 (cur->nodesetval->nodeTab == NULL)) {
5790 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5791 } else {
5792 xmlNodePtr tmp;
5793 int i = 0;
5794
5795 tmp = cur->nodesetval->nodeTab[0];
5796 if (tmp != NULL) {
5797 tmp = tmp->children;
5798 while (tmp != NULL) {
5799 tmp = tmp->next;
5800 i++;
5801 }
5802 }
5803 valuePush(ctxt, xmlXPathNewFloat((double) i));
5804 }
5805 }
Owen Taylor3473f882001-02-23 17:55:21 +00005806 xmlXPathFreeObject(cur);
5807}
5808
5809/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005810 * xmlXPathGetElementsByIds:
5811 * @doc: the document
5812 * @ids: a whitespace separated list of IDs
5813 *
5814 * Selects elements by their unique ID.
5815 *
5816 * Returns a node-set of selected elements.
5817 */
5818static xmlNodeSetPtr
5819xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5820 xmlNodeSetPtr ret;
5821 const xmlChar *cur = ids;
5822 xmlChar *ID;
5823 xmlAttrPtr attr;
5824 xmlNodePtr elem = NULL;
5825
5826 ret = xmlXPathNodeSetCreate(NULL);
5827
5828 while (IS_BLANK(*cur)) cur++;
5829 while (*cur != 0) {
5830 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
5831 (*cur == '.') || (*cur == '-') ||
5832 (*cur == '_') || (*cur == ':') ||
5833 (IS_COMBINING(*cur)) ||
5834 (IS_EXTENDER(*cur)))
5835 cur++;
5836
5837 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
5838
5839 ID = xmlStrndup(ids, cur - ids);
5840 attr = xmlGetID(doc, ID);
5841 if (attr != NULL) {
5842 elem = attr->parent;
5843 xmlXPathNodeSetAdd(ret, elem);
5844 }
5845 if (ID != NULL)
5846 xmlFree(ID);
5847
5848 while (IS_BLANK(*cur)) cur++;
5849 ids = cur;
5850 }
5851 return(ret);
5852}
5853
5854/**
Owen Taylor3473f882001-02-23 17:55:21 +00005855 * xmlXPathIdFunction:
5856 * @ctxt: the XPath Parser context
5857 * @nargs: the number of arguments
5858 *
5859 * Implement the id() XPath function
5860 * node-set id(object)
5861 * The id function selects elements by their unique ID
5862 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
5863 * then the result is the union of the result of applying id to the
5864 * string value of each of the nodes in the argument node-set. When the
5865 * argument to id is of any other type, the argument is converted to a
5866 * string as if by a call to the string function; the string is split
5867 * into a whitespace-separated list of tokens (whitespace is any sequence
5868 * of characters matching the production S); the result is a node-set
5869 * containing the elements in the same document as the context node that
5870 * have a unique ID equal to any of the tokens in the list.
5871 */
5872void
5873xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005874 xmlChar *tokens;
5875 xmlNodeSetPtr ret;
5876 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00005877
5878 CHECK_ARITY(1);
5879 obj = valuePop(ctxt);
5880 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00005881 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005882 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00005883 int i;
5884
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005885 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005886
Daniel Veillard911f49a2001-04-07 15:39:35 +00005887 if (obj->nodesetval != NULL) {
5888 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005889 tokens =
5890 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
5891 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
5892 ret = xmlXPathNodeSetMerge(ret, ns);
5893 xmlXPathFreeNodeSet(ns);
5894 if (tokens != NULL)
5895 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00005896 }
Owen Taylor3473f882001-02-23 17:55:21 +00005897 }
5898
5899 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005900 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005901 return;
5902 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005903 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00005904
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005905 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
5906 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005907
Owen Taylor3473f882001-02-23 17:55:21 +00005908 xmlXPathFreeObject(obj);
5909 return;
5910}
5911
5912/**
5913 * xmlXPathLocalNameFunction:
5914 * @ctxt: the XPath Parser context
5915 * @nargs: the number of arguments
5916 *
5917 * Implement the local-name() XPath function
5918 * string local-name(node-set?)
5919 * The local-name function returns a string containing the local part
5920 * of the name of the node in the argument node-set that is first in
5921 * document order. If the node-set is empty or the first node has no
5922 * name, an empty string is returned. If the argument is omitted it
5923 * defaults to the context node.
5924 */
5925void
5926xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5927 xmlXPathObjectPtr cur;
5928
5929 if (nargs == 0) {
5930 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5931 nargs = 1;
5932 }
5933
5934 CHECK_ARITY(1);
5935 if ((ctxt->value == NULL) ||
5936 ((ctxt->value->type != XPATH_NODESET) &&
5937 (ctxt->value->type != XPATH_XSLT_TREE)))
5938 XP_ERROR(XPATH_INVALID_TYPE);
5939 cur = valuePop(ctxt);
5940
Daniel Veillard911f49a2001-04-07 15:39:35 +00005941 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005942 valuePush(ctxt, xmlXPathNewCString(""));
5943 } else {
5944 int i = 0; /* Should be first in document order !!!!! */
5945 switch (cur->nodesetval->nodeTab[i]->type) {
5946 case XML_ELEMENT_NODE:
5947 case XML_ATTRIBUTE_NODE:
5948 case XML_PI_NODE:
5949 valuePush(ctxt,
5950 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
5951 break;
5952 case XML_NAMESPACE_DECL:
5953 valuePush(ctxt, xmlXPathNewString(
5954 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
5955 break;
5956 default:
5957 valuePush(ctxt, xmlXPathNewCString(""));
5958 }
5959 }
5960 xmlXPathFreeObject(cur);
5961}
5962
5963/**
5964 * xmlXPathNamespaceURIFunction:
5965 * @ctxt: the XPath Parser context
5966 * @nargs: the number of arguments
5967 *
5968 * Implement the namespace-uri() XPath function
5969 * string namespace-uri(node-set?)
5970 * The namespace-uri function returns a string containing the
5971 * namespace URI of the expanded name of the node in the argument
5972 * node-set that is first in document order. If the node-set is empty,
5973 * the first node has no name, or the expanded name has no namespace
5974 * URI, an empty string is returned. If the argument is omitted it
5975 * defaults to the context node.
5976 */
5977void
5978xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5979 xmlXPathObjectPtr cur;
5980
5981 if (nargs == 0) {
5982 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5983 nargs = 1;
5984 }
5985 CHECK_ARITY(1);
5986 if ((ctxt->value == NULL) ||
5987 ((ctxt->value->type != XPATH_NODESET) &&
5988 (ctxt->value->type != XPATH_XSLT_TREE)))
5989 XP_ERROR(XPATH_INVALID_TYPE);
5990 cur = valuePop(ctxt);
5991
Daniel Veillard911f49a2001-04-07 15:39:35 +00005992 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005993 valuePush(ctxt, xmlXPathNewCString(""));
5994 } else {
5995 int i = 0; /* Should be first in document order !!!!! */
5996 switch (cur->nodesetval->nodeTab[i]->type) {
5997 case XML_ELEMENT_NODE:
5998 case XML_ATTRIBUTE_NODE:
5999 if (cur->nodesetval->nodeTab[i]->ns == NULL)
6000 valuePush(ctxt, xmlXPathNewCString(""));
6001 else
6002 valuePush(ctxt, xmlXPathNewString(
6003 cur->nodesetval->nodeTab[i]->ns->href));
6004 break;
6005 default:
6006 valuePush(ctxt, xmlXPathNewCString(""));
6007 }
6008 }
6009 xmlXPathFreeObject(cur);
6010}
6011
6012/**
6013 * xmlXPathNameFunction:
6014 * @ctxt: the XPath Parser context
6015 * @nargs: the number of arguments
6016 *
6017 * Implement the name() XPath function
6018 * string name(node-set?)
6019 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006020 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00006021 * order. The QName must represent the name with respect to the namespace
6022 * declarations in effect on the node whose name is being represented.
6023 * Typically, this will be the form in which the name occurred in the XML
6024 * source. This need not be the case if there are namespace declarations
6025 * in effect on the node that associate multiple prefixes with the same
6026 * namespace. However, an implementation may include information about
6027 * the original prefix in its representation of nodes; in this case, an
6028 * implementation can ensure that the returned string is always the same
6029 * as the QName used in the XML source. If the argument it omitted it
6030 * defaults to the context node.
6031 * Libxml keep the original prefix so the "real qualified name" used is
6032 * returned.
6033 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006034static void
Daniel Veillard04383752001-07-08 14:27:15 +00006035xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
6036{
Owen Taylor3473f882001-02-23 17:55:21 +00006037 xmlXPathObjectPtr cur;
6038
6039 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00006040 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6041 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006042 }
6043
6044 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00006045 if ((ctxt->value == NULL) ||
6046 ((ctxt->value->type != XPATH_NODESET) &&
6047 (ctxt->value->type != XPATH_XSLT_TREE)))
6048 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006049 cur = valuePop(ctxt);
6050
Daniel Veillard911f49a2001-04-07 15:39:35 +00006051 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006052 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00006053 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006054 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00006055
Daniel Veillard04383752001-07-08 14:27:15 +00006056 switch (cur->nodesetval->nodeTab[i]->type) {
6057 case XML_ELEMENT_NODE:
6058 case XML_ATTRIBUTE_NODE:
6059 if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6060 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL))
6061 valuePush(ctxt,
6062 xmlXPathNewString(cur->nodesetval->
6063 nodeTab[i]->name));
6064
6065 else {
6066 char name[2000];
6067
6068 snprintf(name, sizeof(name), "%s:%s",
6069 (char *) cur->nodesetval->nodeTab[i]->ns->
6070 prefix,
6071 (char *) cur->nodesetval->nodeTab[i]->name);
6072 name[sizeof(name) - 1] = 0;
6073 valuePush(ctxt, xmlXPathNewCString(name));
6074 }
6075 break;
6076 default:
6077 valuePush(ctxt,
6078 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6079 xmlXPathLocalNameFunction(ctxt, 1);
6080 }
Owen Taylor3473f882001-02-23 17:55:21 +00006081 }
6082 xmlXPathFreeObject(cur);
6083}
6084
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006085
6086/**
Owen Taylor3473f882001-02-23 17:55:21 +00006087 * xmlXPathStringFunction:
6088 * @ctxt: the XPath Parser context
6089 * @nargs: the number of arguments
6090 *
6091 * Implement the string() XPath function
6092 * string string(object?)
6093 * he string function converts an object to a string as follows:
6094 * - A node-set is converted to a string by returning the value of
6095 * the node in the node-set that is first in document order.
6096 * If the node-set is empty, an empty string is returned.
6097 * - A number is converted to a string as follows
6098 * + NaN is converted to the string NaN
6099 * + positive zero is converted to the string 0
6100 * + negative zero is converted to the string 0
6101 * + positive infinity is converted to the string Infinity
6102 * + negative infinity is converted to the string -Infinity
6103 * + if the number is an integer, the number is represented in
6104 * decimal form as a Number with no decimal point and no leading
6105 * zeros, preceded by a minus sign (-) if the number is negative
6106 * + otherwise, the number is represented in decimal form as a
6107 * Number including a decimal point with at least one digit
6108 * before the decimal point and at least one digit after the
6109 * decimal point, preceded by a minus sign (-) if the number
6110 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006111 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00006112 * before the decimal point; beyond the one required digit
6113 * after the decimal point there must be as many, but only as
6114 * many, more digits as are needed to uniquely distinguish the
6115 * number from all other IEEE 754 numeric values.
6116 * - The boolean false value is converted to the string false.
6117 * The boolean true value is converted to the string true.
6118 *
6119 * If the argument is omitted, it defaults to a node-set with the
6120 * context node as its only member.
6121 */
6122void
6123xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6124 xmlXPathObjectPtr cur;
6125
6126 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006127 valuePush(ctxt,
6128 xmlXPathWrapString(
6129 xmlXPathCastNodeToString(ctxt->context->node)));
6130 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006131 }
6132
6133 CHECK_ARITY(1);
6134 cur = valuePop(ctxt);
6135 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006136 cur = xmlXPathConvertString(cur);
6137 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006138}
6139
6140/**
6141 * xmlXPathStringLengthFunction:
6142 * @ctxt: the XPath Parser context
6143 * @nargs: the number of arguments
6144 *
6145 * Implement the string-length() XPath function
6146 * number string-length(string?)
6147 * The string-length returns the number of characters in the string
6148 * (see [3.6 Strings]). If the argument is omitted, it defaults to
6149 * the context node converted to a string, in other words the value
6150 * of the context node.
6151 */
6152void
6153xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6154 xmlXPathObjectPtr cur;
6155
6156 if (nargs == 0) {
6157 if (ctxt->context->node == NULL) {
6158 valuePush(ctxt, xmlXPathNewFloat(0));
6159 } else {
6160 xmlChar *content;
6161
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006162 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006163 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00006164 xmlFree(content);
6165 }
6166 return;
6167 }
6168 CHECK_ARITY(1);
6169 CAST_TO_STRING;
6170 CHECK_TYPE(XPATH_STRING);
6171 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006172 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00006173 xmlXPathFreeObject(cur);
6174}
6175
6176/**
6177 * xmlXPathConcatFunction:
6178 * @ctxt: the XPath Parser context
6179 * @nargs: the number of arguments
6180 *
6181 * Implement the concat() XPath function
6182 * string concat(string, string, string*)
6183 * The concat function returns the concatenation of its arguments.
6184 */
6185void
6186xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6187 xmlXPathObjectPtr cur, newobj;
6188 xmlChar *tmp;
6189
6190 if (nargs < 2) {
6191 CHECK_ARITY(2);
6192 }
6193
6194 CAST_TO_STRING;
6195 cur = valuePop(ctxt);
6196 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6197 xmlXPathFreeObject(cur);
6198 return;
6199 }
6200 nargs--;
6201
6202 while (nargs > 0) {
6203 CAST_TO_STRING;
6204 newobj = valuePop(ctxt);
6205 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6206 xmlXPathFreeObject(newobj);
6207 xmlXPathFreeObject(cur);
6208 XP_ERROR(XPATH_INVALID_TYPE);
6209 }
6210 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6211 newobj->stringval = cur->stringval;
6212 cur->stringval = tmp;
6213
6214 xmlXPathFreeObject(newobj);
6215 nargs--;
6216 }
6217 valuePush(ctxt, cur);
6218}
6219
6220/**
6221 * xmlXPathContainsFunction:
6222 * @ctxt: the XPath Parser context
6223 * @nargs: the number of arguments
6224 *
6225 * Implement the contains() XPath function
6226 * boolean contains(string, string)
6227 * The contains function returns true if the first argument string
6228 * contains the second argument string, and otherwise returns false.
6229 */
6230void
6231xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6232 xmlXPathObjectPtr hay, needle;
6233
6234 CHECK_ARITY(2);
6235 CAST_TO_STRING;
6236 CHECK_TYPE(XPATH_STRING);
6237 needle = valuePop(ctxt);
6238 CAST_TO_STRING;
6239 hay = valuePop(ctxt);
6240 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6241 xmlXPathFreeObject(hay);
6242 xmlXPathFreeObject(needle);
6243 XP_ERROR(XPATH_INVALID_TYPE);
6244 }
6245 if (xmlStrstr(hay->stringval, needle->stringval))
6246 valuePush(ctxt, xmlXPathNewBoolean(1));
6247 else
6248 valuePush(ctxt, xmlXPathNewBoolean(0));
6249 xmlXPathFreeObject(hay);
6250 xmlXPathFreeObject(needle);
6251}
6252
6253/**
6254 * xmlXPathStartsWithFunction:
6255 * @ctxt: the XPath Parser context
6256 * @nargs: the number of arguments
6257 *
6258 * Implement the starts-with() XPath function
6259 * boolean starts-with(string, string)
6260 * The starts-with function returns true if the first argument string
6261 * starts with the second argument string, and otherwise returns false.
6262 */
6263void
6264xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6265 xmlXPathObjectPtr hay, needle;
6266 int n;
6267
6268 CHECK_ARITY(2);
6269 CAST_TO_STRING;
6270 CHECK_TYPE(XPATH_STRING);
6271 needle = valuePop(ctxt);
6272 CAST_TO_STRING;
6273 hay = valuePop(ctxt);
6274 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6275 xmlXPathFreeObject(hay);
6276 xmlXPathFreeObject(needle);
6277 XP_ERROR(XPATH_INVALID_TYPE);
6278 }
6279 n = xmlStrlen(needle->stringval);
6280 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6281 valuePush(ctxt, xmlXPathNewBoolean(0));
6282 else
6283 valuePush(ctxt, xmlXPathNewBoolean(1));
6284 xmlXPathFreeObject(hay);
6285 xmlXPathFreeObject(needle);
6286}
6287
6288/**
6289 * xmlXPathSubstringFunction:
6290 * @ctxt: the XPath Parser context
6291 * @nargs: the number of arguments
6292 *
6293 * Implement the substring() XPath function
6294 * string substring(string, number, number?)
6295 * The substring function returns the substring of the first argument
6296 * starting at the position specified in the second argument with
6297 * length specified in the third argument. For example,
6298 * substring("12345",2,3) returns "234". If the third argument is not
6299 * specified, it returns the substring starting at the position specified
6300 * in the second argument and continuing to the end of the string. For
6301 * example, substring("12345",2) returns "2345". More precisely, each
6302 * character in the string (see [3.6 Strings]) is considered to have a
6303 * numeric position: the position of the first character is 1, the position
6304 * of the second character is 2 and so on. The returned substring contains
6305 * those characters for which the position of the character is greater than
6306 * or equal to the second argument and, if the third argument is specified,
6307 * less than the sum of the second and third arguments; the comparisons
6308 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6309 * - substring("12345", 1.5, 2.6) returns "234"
6310 * - substring("12345", 0, 3) returns "12"
6311 * - substring("12345", 0 div 0, 3) returns ""
6312 * - substring("12345", 1, 0 div 0) returns ""
6313 * - substring("12345", -42, 1 div 0) returns "12345"
6314 * - substring("12345", -1 div 0, 1 div 0) returns ""
6315 */
6316void
6317xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6318 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006319 double le=0, in;
6320 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006321 xmlChar *ret;
6322
Owen Taylor3473f882001-02-23 17:55:21 +00006323 if (nargs < 2) {
6324 CHECK_ARITY(2);
6325 }
6326 if (nargs > 3) {
6327 CHECK_ARITY(3);
6328 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006329 /*
6330 * take care of possible last (position) argument
6331 */
Owen Taylor3473f882001-02-23 17:55:21 +00006332 if (nargs == 3) {
6333 CAST_TO_NUMBER;
6334 CHECK_TYPE(XPATH_NUMBER);
6335 len = valuePop(ctxt);
6336 le = len->floatval;
6337 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006338 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006339
Owen Taylor3473f882001-02-23 17:55:21 +00006340 CAST_TO_NUMBER;
6341 CHECK_TYPE(XPATH_NUMBER);
6342 start = valuePop(ctxt);
6343 in = start->floatval;
6344 xmlXPathFreeObject(start);
6345 CAST_TO_STRING;
6346 CHECK_TYPE(XPATH_STRING);
6347 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006348 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006349
Daniel Veillard97ac1312001-05-30 19:14:17 +00006350 /*
6351 * If last pos not present, calculate last position
6352 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006353 if (nargs != 3) {
6354 le = (double)m;
6355 if (in < 1.0)
6356 in = 1.0;
6357 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006358
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006359 /* Need to check for the special cases where either
6360 * the index is NaN, the length is NaN, or both
6361 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00006362 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006363 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006364 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00006365 * To meet the requirements of the spec, the arguments
6366 * must be converted to integer format before
6367 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006368 *
Daniel Veillard9e412302002-06-10 15:59:44 +00006369 * First we go to integer form, rounding up
6370 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006371 */
6372 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00006373 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00006374
Daniel Veillard9e412302002-06-10 15:59:44 +00006375 if (xmlXPathIsInf(le) == 1) {
6376 l = m;
6377 if (i < 1)
6378 i = 1;
6379 }
6380 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
6381 l = 0;
6382 else {
6383 l = (int) le;
6384 if (((double)l)+0.5 <= le) l++;
6385 }
6386
6387 /* Now we normalize inidices */
6388 i -= 1;
6389 l += i;
6390 if (i < 0)
6391 i = 0;
6392 if (l > m)
6393 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00006394
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006395 /* number of chars to copy */
6396 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00006397
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006398 ret = xmlUTF8Strsub(str->stringval, i, l);
6399 }
6400 else {
6401 ret = NULL;
6402 }
6403
Owen Taylor3473f882001-02-23 17:55:21 +00006404 if (ret == NULL)
6405 valuePush(ctxt, xmlXPathNewCString(""));
6406 else {
6407 valuePush(ctxt, xmlXPathNewString(ret));
6408 xmlFree(ret);
6409 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006410
Owen Taylor3473f882001-02-23 17:55:21 +00006411 xmlXPathFreeObject(str);
6412}
6413
6414/**
6415 * xmlXPathSubstringBeforeFunction:
6416 * @ctxt: the XPath Parser context
6417 * @nargs: the number of arguments
6418 *
6419 * Implement the substring-before() XPath function
6420 * string substring-before(string, string)
6421 * The substring-before function returns the substring of the first
6422 * argument string that precedes the first occurrence of the second
6423 * argument string in the first argument string, or the empty string
6424 * if the first argument string does not contain the second argument
6425 * string. For example, substring-before("1999/04/01","/") returns 1999.
6426 */
6427void
6428xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6429 xmlXPathObjectPtr str;
6430 xmlXPathObjectPtr find;
6431 xmlBufferPtr target;
6432 const xmlChar *point;
6433 int offset;
6434
6435 CHECK_ARITY(2);
6436 CAST_TO_STRING;
6437 find = valuePop(ctxt);
6438 CAST_TO_STRING;
6439 str = valuePop(ctxt);
6440
6441 target = xmlBufferCreate();
6442 if (target) {
6443 point = xmlStrstr(str->stringval, find->stringval);
6444 if (point) {
6445 offset = (int)(point - str->stringval);
6446 xmlBufferAdd(target, str->stringval, offset);
6447 }
6448 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6449 xmlBufferFree(target);
6450 }
6451
6452 xmlXPathFreeObject(str);
6453 xmlXPathFreeObject(find);
6454}
6455
6456/**
6457 * xmlXPathSubstringAfterFunction:
6458 * @ctxt: the XPath Parser context
6459 * @nargs: the number of arguments
6460 *
6461 * Implement the substring-after() XPath function
6462 * string substring-after(string, string)
6463 * The substring-after function returns the substring of the first
6464 * argument string that follows the first occurrence of the second
6465 * argument string in the first argument string, or the empty stringi
6466 * if the first argument string does not contain the second argument
6467 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6468 * and substring-after("1999/04/01","19") returns 99/04/01.
6469 */
6470void
6471xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6472 xmlXPathObjectPtr str;
6473 xmlXPathObjectPtr find;
6474 xmlBufferPtr target;
6475 const xmlChar *point;
6476 int offset;
6477
6478 CHECK_ARITY(2);
6479 CAST_TO_STRING;
6480 find = valuePop(ctxt);
6481 CAST_TO_STRING;
6482 str = valuePop(ctxt);
6483
6484 target = xmlBufferCreate();
6485 if (target) {
6486 point = xmlStrstr(str->stringval, find->stringval);
6487 if (point) {
6488 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6489 xmlBufferAdd(target, &str->stringval[offset],
6490 xmlStrlen(str->stringval) - offset);
6491 }
6492 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6493 xmlBufferFree(target);
6494 }
6495
6496 xmlXPathFreeObject(str);
6497 xmlXPathFreeObject(find);
6498}
6499
6500/**
6501 * xmlXPathNormalizeFunction:
6502 * @ctxt: the XPath Parser context
6503 * @nargs: the number of arguments
6504 *
6505 * Implement the normalize-space() XPath function
6506 * string normalize-space(string?)
6507 * The normalize-space function returns the argument string with white
6508 * space normalized by stripping leading and trailing whitespace
6509 * and replacing sequences of whitespace characters by a single
6510 * space. Whitespace characters are the same allowed by the S production
6511 * in XML. If the argument is omitted, it defaults to the context
6512 * node converted to a string, in other words the value of the context node.
6513 */
6514void
6515xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6516 xmlXPathObjectPtr obj = NULL;
6517 xmlChar *source = NULL;
6518 xmlBufferPtr target;
6519 xmlChar blank;
6520
6521 if (nargs == 0) {
6522 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006523 valuePush(ctxt,
6524 xmlXPathWrapString(
6525 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006526 nargs = 1;
6527 }
6528
6529 CHECK_ARITY(1);
6530 CAST_TO_STRING;
6531 CHECK_TYPE(XPATH_STRING);
6532 obj = valuePop(ctxt);
6533 source = obj->stringval;
6534
6535 target = xmlBufferCreate();
6536 if (target && source) {
6537
6538 /* Skip leading whitespaces */
6539 while (IS_BLANK(*source))
6540 source++;
6541
6542 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6543 blank = 0;
6544 while (*source) {
6545 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006546 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006547 } else {
6548 if (blank) {
6549 xmlBufferAdd(target, &blank, 1);
6550 blank = 0;
6551 }
6552 xmlBufferAdd(target, source, 1);
6553 }
6554 source++;
6555 }
6556
6557 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6558 xmlBufferFree(target);
6559 }
6560 xmlXPathFreeObject(obj);
6561}
6562
6563/**
6564 * xmlXPathTranslateFunction:
6565 * @ctxt: the XPath Parser context
6566 * @nargs: the number of arguments
6567 *
6568 * Implement the translate() XPath function
6569 * string translate(string, string, string)
6570 * The translate function returns the first argument string with
6571 * occurrences of characters in the second argument string replaced
6572 * by the character at the corresponding position in the third argument
6573 * string. For example, translate("bar","abc","ABC") returns the string
6574 * BAr. If there is a character in the second argument string with no
6575 * character at a corresponding position in the third argument string
6576 * (because the second argument string is longer than the third argument
6577 * string), then occurrences of that character in the first argument
6578 * string are removed. For example, translate("--aaa--","abc-","ABC")
6579 * returns "AAA". If a character occurs more than once in second
6580 * argument string, then the first occurrence determines the replacement
6581 * character. If the third argument string is longer than the second
6582 * argument string, then excess characters are ignored.
6583 */
6584void
6585xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006586 xmlXPathObjectPtr str;
6587 xmlXPathObjectPtr from;
6588 xmlXPathObjectPtr to;
6589 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006590 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006591 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006592 xmlChar *point;
6593 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006594
Daniel Veillarde043ee12001-04-16 14:08:07 +00006595 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006596
Daniel Veillarde043ee12001-04-16 14:08:07 +00006597 CAST_TO_STRING;
6598 to = valuePop(ctxt);
6599 CAST_TO_STRING;
6600 from = valuePop(ctxt);
6601 CAST_TO_STRING;
6602 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006603
Daniel Veillarde043ee12001-04-16 14:08:07 +00006604 target = xmlBufferCreate();
6605 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006606 max = xmlUTF8Strlen(to->stringval);
6607 for (cptr = str->stringval; (ch=*cptr); ) {
6608 offset = xmlUTF8Strloc(from->stringval, cptr);
6609 if (offset >= 0) {
6610 if (offset < max) {
6611 point = xmlUTF8Strpos(to->stringval, offset);
6612 if (point)
6613 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6614 }
6615 } else
6616 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6617
6618 /* Step to next character in input */
6619 cptr++;
6620 if ( ch & 0x80 ) {
6621 /* if not simple ascii, verify proper format */
6622 if ( (ch & 0xc0) != 0xc0 ) {
6623 xmlGenericError(xmlGenericErrorContext,
6624 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6625 break;
6626 }
6627 /* then skip over remaining bytes for this char */
6628 while ( (ch <<= 1) & 0x80 )
6629 if ( (*cptr++ & 0xc0) != 0x80 ) {
6630 xmlGenericError(xmlGenericErrorContext,
6631 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6632 break;
6633 }
6634 if (ch & 0x80) /* must have had error encountered */
6635 break;
6636 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006637 }
Owen Taylor3473f882001-02-23 17:55:21 +00006638 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006639 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6640 xmlBufferFree(target);
6641 xmlXPathFreeObject(str);
6642 xmlXPathFreeObject(from);
6643 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006644}
6645
6646/**
6647 * xmlXPathBooleanFunction:
6648 * @ctxt: the XPath Parser context
6649 * @nargs: the number of arguments
6650 *
6651 * Implement the boolean() XPath function
6652 * boolean boolean(object)
6653 * he boolean function converts its argument to a boolean as follows:
6654 * - a number is true if and only if it is neither positive or
6655 * negative zero nor NaN
6656 * - a node-set is true if and only if it is non-empty
6657 * - a string is true if and only if its length is non-zero
6658 */
6659void
6660xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6661 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006662
6663 CHECK_ARITY(1);
6664 cur = valuePop(ctxt);
6665 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006666 cur = xmlXPathConvertBoolean(cur);
6667 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006668}
6669
6670/**
6671 * xmlXPathNotFunction:
6672 * @ctxt: the XPath Parser context
6673 * @nargs: the number of arguments
6674 *
6675 * Implement the not() XPath function
6676 * boolean not(boolean)
6677 * The not function returns true if its argument is false,
6678 * and false otherwise.
6679 */
6680void
6681xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6682 CHECK_ARITY(1);
6683 CAST_TO_BOOLEAN;
6684 CHECK_TYPE(XPATH_BOOLEAN);
6685 ctxt->value->boolval = ! ctxt->value->boolval;
6686}
6687
6688/**
6689 * xmlXPathTrueFunction:
6690 * @ctxt: the XPath Parser context
6691 * @nargs: the number of arguments
6692 *
6693 * Implement the true() XPath function
6694 * boolean true()
6695 */
6696void
6697xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6698 CHECK_ARITY(0);
6699 valuePush(ctxt, xmlXPathNewBoolean(1));
6700}
6701
6702/**
6703 * xmlXPathFalseFunction:
6704 * @ctxt: the XPath Parser context
6705 * @nargs: the number of arguments
6706 *
6707 * Implement the false() XPath function
6708 * boolean false()
6709 */
6710void
6711xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6712 CHECK_ARITY(0);
6713 valuePush(ctxt, xmlXPathNewBoolean(0));
6714}
6715
6716/**
6717 * xmlXPathLangFunction:
6718 * @ctxt: the XPath Parser context
6719 * @nargs: the number of arguments
6720 *
6721 * Implement the lang() XPath function
6722 * boolean lang(string)
6723 * The lang function returns true or false depending on whether the
6724 * language of the context node as specified by xml:lang attributes
6725 * is the same as or is a sublanguage of the language specified by
6726 * the argument string. The language of the context node is determined
6727 * by the value of the xml:lang attribute on the context node, or, if
6728 * the context node has no xml:lang attribute, by the value of the
6729 * xml:lang attribute on the nearest ancestor of the context node that
6730 * has an xml:lang attribute. If there is no such attribute, then lang
6731 * returns false. If there is such an attribute, then lang returns
6732 * true if the attribute value is equal to the argument ignoring case,
6733 * or if there is some suffix starting with - such that the attribute
6734 * value is equal to the argument ignoring that suffix of the attribute
6735 * value and ignoring case.
6736 */
6737void
6738xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6739 xmlXPathObjectPtr val;
6740 const xmlChar *theLang;
6741 const xmlChar *lang;
6742 int ret = 0;
6743 int i;
6744
6745 CHECK_ARITY(1);
6746 CAST_TO_STRING;
6747 CHECK_TYPE(XPATH_STRING);
6748 val = valuePop(ctxt);
6749 lang = val->stringval;
6750 theLang = xmlNodeGetLang(ctxt->context->node);
6751 if ((theLang != NULL) && (lang != NULL)) {
6752 for (i = 0;lang[i] != 0;i++)
6753 if (toupper(lang[i]) != toupper(theLang[i]))
6754 goto not_equal;
6755 ret = 1;
6756 }
6757not_equal:
6758 xmlXPathFreeObject(val);
6759 valuePush(ctxt, xmlXPathNewBoolean(ret));
6760}
6761
6762/**
6763 * xmlXPathNumberFunction:
6764 * @ctxt: the XPath Parser context
6765 * @nargs: the number of arguments
6766 *
6767 * Implement the number() XPath function
6768 * number number(object?)
6769 */
6770void
6771xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6772 xmlXPathObjectPtr cur;
6773 double res;
6774
6775 if (nargs == 0) {
6776 if (ctxt->context->node == NULL) {
6777 valuePush(ctxt, xmlXPathNewFloat(0.0));
6778 } else {
6779 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6780
6781 res = xmlXPathStringEvalNumber(content);
6782 valuePush(ctxt, xmlXPathNewFloat(res));
6783 xmlFree(content);
6784 }
6785 return;
6786 }
6787
6788 CHECK_ARITY(1);
6789 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006790 cur = xmlXPathConvertNumber(cur);
6791 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006792}
6793
6794/**
6795 * xmlXPathSumFunction:
6796 * @ctxt: the XPath Parser context
6797 * @nargs: the number of arguments
6798 *
6799 * Implement the sum() XPath function
6800 * number sum(node-set)
6801 * The sum function returns the sum of the values of the nodes in
6802 * the argument node-set.
6803 */
6804void
6805xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6806 xmlXPathObjectPtr cur;
6807 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006808 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00006809
6810 CHECK_ARITY(1);
6811 if ((ctxt->value == NULL) ||
6812 ((ctxt->value->type != XPATH_NODESET) &&
6813 (ctxt->value->type != XPATH_XSLT_TREE)))
6814 XP_ERROR(XPATH_INVALID_TYPE);
6815 cur = valuePop(ctxt);
6816
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006817 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006818 valuePush(ctxt, xmlXPathNewFloat(0.0));
6819 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006820 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
6821 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006822 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006823 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00006824 }
6825 xmlXPathFreeObject(cur);
6826}
6827
6828/**
6829 * xmlXPathFloorFunction:
6830 * @ctxt: the XPath Parser context
6831 * @nargs: the number of arguments
6832 *
6833 * Implement the floor() XPath function
6834 * number floor(number)
6835 * The floor function returns the largest (closest to positive infinity)
6836 * number that is not greater than the argument and that is an integer.
6837 */
6838void
6839xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006840 double f;
6841
Owen Taylor3473f882001-02-23 17:55:21 +00006842 CHECK_ARITY(1);
6843 CAST_TO_NUMBER;
6844 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006845
6846 f = (double)((int) ctxt->value->floatval);
6847 if (f != ctxt->value->floatval) {
6848 if (ctxt->value->floatval > 0)
6849 ctxt->value->floatval = f;
6850 else
6851 ctxt->value->floatval = f - 1;
6852 }
Owen Taylor3473f882001-02-23 17:55:21 +00006853}
6854
6855/**
6856 * xmlXPathCeilingFunction:
6857 * @ctxt: the XPath Parser context
6858 * @nargs: the number of arguments
6859 *
6860 * Implement the ceiling() XPath function
6861 * number ceiling(number)
6862 * The ceiling function returns the smallest (closest to negative infinity)
6863 * number that is not less than the argument and that is an integer.
6864 */
6865void
6866xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6867 double f;
6868
6869 CHECK_ARITY(1);
6870 CAST_TO_NUMBER;
6871 CHECK_TYPE(XPATH_NUMBER);
6872
6873#if 0
6874 ctxt->value->floatval = ceil(ctxt->value->floatval);
6875#else
6876 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006877 if (f != ctxt->value->floatval) {
6878 if (ctxt->value->floatval > 0)
6879 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00006880 else {
6881 if (ctxt->value->floatval < 0 && f == 0)
6882 ctxt->value->floatval = xmlXPathNZERO;
6883 else
6884 ctxt->value->floatval = f;
6885 }
6886
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006887 }
Owen Taylor3473f882001-02-23 17:55:21 +00006888#endif
6889}
6890
6891/**
6892 * xmlXPathRoundFunction:
6893 * @ctxt: the XPath Parser context
6894 * @nargs: the number of arguments
6895 *
6896 * Implement the round() XPath function
6897 * number round(number)
6898 * The round function returns the number that is closest to the
6899 * argument and that is an integer. If there are two such numbers,
6900 * then the one that is even is returned.
6901 */
6902void
6903xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6904 double f;
6905
6906 CHECK_ARITY(1);
6907 CAST_TO_NUMBER;
6908 CHECK_TYPE(XPATH_NUMBER);
6909
Daniel Veillardcda96922001-08-21 10:56:31 +00006910 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
6911 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
6912 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00006913 (ctxt->value->floatval == 0.0))
6914 return;
6915
Owen Taylor3473f882001-02-23 17:55:21 +00006916 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006917 if (ctxt->value->floatval < 0) {
6918 if (ctxt->value->floatval < f - 0.5)
6919 ctxt->value->floatval = f - 1;
6920 else
6921 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00006922 if (ctxt->value->floatval == 0)
6923 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006924 } else {
6925 if (ctxt->value->floatval < f + 0.5)
6926 ctxt->value->floatval = f;
6927 else
6928 ctxt->value->floatval = f + 1;
6929 }
Owen Taylor3473f882001-02-23 17:55:21 +00006930}
6931
6932/************************************************************************
6933 * *
6934 * The Parser *
6935 * *
6936 ************************************************************************/
6937
6938/*
6939 * a couple of forward declarations since we use a recursive call based
6940 * implementation.
6941 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006942static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006943static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006944static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006945static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00006946static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
6947 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00006948
6949/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00006950 * xmlXPathCurrentChar:
6951 * @ctxt: the XPath parser context
6952 * @cur: pointer to the beginning of the char
6953 * @len: pointer to the length of the char read
6954 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006955 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00006956 * bytes in the input buffer.
6957 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006958 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00006959 */
6960
6961static int
6962xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
6963 unsigned char c;
6964 unsigned int val;
6965 const xmlChar *cur;
6966
6967 if (ctxt == NULL)
6968 return(0);
6969 cur = ctxt->cur;
6970
6971 /*
6972 * We are supposed to handle UTF8, check it's valid
6973 * From rfc2044: encoding of the Unicode values on UTF-8:
6974 *
6975 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
6976 * 0000 0000-0000 007F 0xxxxxxx
6977 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
6978 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
6979 *
6980 * Check for the 0x110000 limit too
6981 */
6982 c = *cur;
6983 if (c & 0x80) {
6984 if ((cur[1] & 0xc0) != 0x80)
6985 goto encoding_error;
6986 if ((c & 0xe0) == 0xe0) {
6987
6988 if ((cur[2] & 0xc0) != 0x80)
6989 goto encoding_error;
6990 if ((c & 0xf0) == 0xf0) {
6991 if (((c & 0xf8) != 0xf0) ||
6992 ((cur[3] & 0xc0) != 0x80))
6993 goto encoding_error;
6994 /* 4-byte code */
6995 *len = 4;
6996 val = (cur[0] & 0x7) << 18;
6997 val |= (cur[1] & 0x3f) << 12;
6998 val |= (cur[2] & 0x3f) << 6;
6999 val |= cur[3] & 0x3f;
7000 } else {
7001 /* 3-byte code */
7002 *len = 3;
7003 val = (cur[0] & 0xf) << 12;
7004 val |= (cur[1] & 0x3f) << 6;
7005 val |= cur[2] & 0x3f;
7006 }
7007 } else {
7008 /* 2-byte code */
7009 *len = 2;
7010 val = (cur[0] & 0x1f) << 6;
7011 val |= cur[1] & 0x3f;
7012 }
7013 if (!IS_CHAR(val)) {
7014 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
7015 }
7016 return(val);
7017 } else {
7018 /* 1-byte code */
7019 *len = 1;
7020 return((int) *cur);
7021 }
7022encoding_error:
7023 /*
7024 * If we detect an UTF8 error that probably mean that the
7025 * input encoding didn't get properly advertized in the
7026 * declaration header. Report the error and switch the encoding
7027 * to ISO-Latin-1 (if you don't like this policy, just declare the
7028 * encoding !)
7029 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00007030 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00007031 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007032}
7033
7034/**
Owen Taylor3473f882001-02-23 17:55:21 +00007035 * xmlXPathParseNCName:
7036 * @ctxt: the XPath Parser context
7037 *
7038 * parse an XML namespace non qualified name.
7039 *
7040 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7041 *
7042 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7043 * CombiningChar | Extender
7044 *
7045 * Returns the namespace name or NULL
7046 */
7047
7048xmlChar *
7049xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00007050 const xmlChar *in;
7051 xmlChar *ret;
7052 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007053
Daniel Veillard2156a562001-04-28 12:24:34 +00007054 /*
7055 * Accelerator for simple ASCII names
7056 */
7057 in = ctxt->cur;
7058 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7059 ((*in >= 0x41) && (*in <= 0x5A)) ||
7060 (*in == '_')) {
7061 in++;
7062 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7063 ((*in >= 0x41) && (*in <= 0x5A)) ||
7064 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00007065 (*in == '_') || (*in == '.') ||
7066 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00007067 in++;
7068 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7069 (*in == '[') || (*in == ']') || (*in == ':') ||
7070 (*in == '@') || (*in == '*')) {
7071 count = in - ctxt->cur;
7072 if (count == 0)
7073 return(NULL);
7074 ret = xmlStrndup(ctxt->cur, count);
7075 ctxt->cur = in;
7076 return(ret);
7077 }
7078 }
7079 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00007080}
7081
Daniel Veillard2156a562001-04-28 12:24:34 +00007082
Owen Taylor3473f882001-02-23 17:55:21 +00007083/**
7084 * xmlXPathParseQName:
7085 * @ctxt: the XPath Parser context
7086 * @prefix: a xmlChar **
7087 *
7088 * parse an XML qualified name
7089 *
7090 * [NS 5] QName ::= (Prefix ':')? LocalPart
7091 *
7092 * [NS 6] Prefix ::= NCName
7093 *
7094 * [NS 7] LocalPart ::= NCName
7095 *
7096 * Returns the function returns the local part, and prefix is updated
7097 * to get the Prefix if any.
7098 */
7099
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007100static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007101xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7102 xmlChar *ret = NULL;
7103
7104 *prefix = NULL;
7105 ret = xmlXPathParseNCName(ctxt);
7106 if (CUR == ':') {
7107 *prefix = ret;
7108 NEXT;
7109 ret = xmlXPathParseNCName(ctxt);
7110 }
7111 return(ret);
7112}
7113
7114/**
7115 * xmlXPathParseName:
7116 * @ctxt: the XPath Parser context
7117 *
7118 * parse an XML name
7119 *
7120 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7121 * CombiningChar | Extender
7122 *
7123 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7124 *
7125 * Returns the namespace name or NULL
7126 */
7127
7128xmlChar *
7129xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007130 const xmlChar *in;
7131 xmlChar *ret;
7132 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007133
Daniel Veillard61d80a22001-04-27 17:13:01 +00007134 /*
7135 * Accelerator for simple ASCII names
7136 */
7137 in = ctxt->cur;
7138 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7139 ((*in >= 0x41) && (*in <= 0x5A)) ||
7140 (*in == '_') || (*in == ':')) {
7141 in++;
7142 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7143 ((*in >= 0x41) && (*in <= 0x5A)) ||
7144 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00007145 (*in == '_') || (*in == '-') ||
7146 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00007147 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007148 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007149 count = in - ctxt->cur;
7150 ret = xmlStrndup(ctxt->cur, count);
7151 ctxt->cur = in;
7152 return(ret);
7153 }
7154 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007155 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00007156}
7157
Daniel Veillard61d80a22001-04-27 17:13:01 +00007158static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00007159xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007160 xmlChar buf[XML_MAX_NAMELEN + 5];
7161 int len = 0, l;
7162 int c;
7163
7164 /*
7165 * Handler for more complex cases
7166 */
7167 c = CUR_CHAR(l);
7168 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00007169 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7170 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00007171 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00007172 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007173 return(NULL);
7174 }
7175
7176 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7177 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7178 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007179 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007180 (IS_COMBINING(c)) ||
7181 (IS_EXTENDER(c)))) {
7182 COPY_BUF(l,buf,len,c);
7183 NEXTL(l);
7184 c = CUR_CHAR(l);
7185 if (len >= XML_MAX_NAMELEN) {
7186 /*
7187 * Okay someone managed to make a huge name, so he's ready to pay
7188 * for the processing speed.
7189 */
7190 xmlChar *buffer;
7191 int max = len * 2;
7192
7193 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
7194 if (buffer == NULL) {
7195 XP_ERROR0(XPATH_MEMORY_ERROR);
7196 }
7197 memcpy(buffer, buf, len);
7198 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7199 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007200 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007201 (IS_COMBINING(c)) ||
7202 (IS_EXTENDER(c))) {
7203 if (len + 10 > max) {
7204 max *= 2;
7205 buffer = (xmlChar *) xmlRealloc(buffer,
7206 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007207 if (buffer == NULL) {
7208 XP_ERROR0(XPATH_MEMORY_ERROR);
7209 }
7210 }
7211 COPY_BUF(l,buffer,len,c);
7212 NEXTL(l);
7213 c = CUR_CHAR(l);
7214 }
7215 buffer[len] = 0;
7216 return(buffer);
7217 }
7218 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007219 if (len == 0)
7220 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007221 return(xmlStrndup(buf, len));
7222}
Daniel Veillard3cd72402002-05-13 10:33:30 +00007223
7224#define MAX_FRAC 20
7225
7226static double my_pow10[MAX_FRAC] = {
7227 1.0, 10.0, 100.0, 1000.0, 10000.0,
7228 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7229 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7230 100000000000000.0,
7231 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
7232 1000000000000000000.0, 10000000000000000000.0
7233};
7234
Owen Taylor3473f882001-02-23 17:55:21 +00007235/**
7236 * xmlXPathStringEvalNumber:
7237 * @str: A string to scan
7238 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00007239 * [30a] Float ::= Number ('e' Digits?)?
7240 *
Owen Taylor3473f882001-02-23 17:55:21 +00007241 * [30] Number ::= Digits ('.' Digits?)?
7242 * | '.' Digits
7243 * [31] Digits ::= [0-9]+
7244 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007245 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00007246 * In complement of the Number expression, this function also handles
7247 * negative values : '-' Number.
7248 *
7249 * Returns the double value.
7250 */
7251double
7252xmlXPathStringEvalNumber(const xmlChar *str) {
7253 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00007254 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007255 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007256 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007257 int exponent = 0;
7258 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007259#ifdef __GNUC__
7260 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007261 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007262#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00007263 if (cur == NULL) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00007264 while (IS_BLANK(*cur)) cur++;
7265 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7266 return(xmlXPathNAN);
7267 }
7268 if (*cur == '-') {
7269 isneg = 1;
7270 cur++;
7271 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007272
7273#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007274 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007275 * tmp/temp is a workaround against a gcc compiler bug
7276 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007277 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007278 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007279 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007280 ret = ret * 10;
7281 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00007282 ok = 1;
7283 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00007284 temp = (double) tmp;
7285 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007286 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007287#else
Daniel Veillard7b416132002-03-07 08:36:03 +00007288 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007289 while ((*cur >= '0') && (*cur <= '9')) {
7290 ret = ret * 10 + (*cur - '0');
7291 ok = 1;
7292 cur++;
7293 }
7294#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007295
Owen Taylor3473f882001-02-23 17:55:21 +00007296 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007297 int v, frac = 0;
7298 double fraction = 0;
7299
Owen Taylor3473f882001-02-23 17:55:21 +00007300 cur++;
7301 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7302 return(xmlXPathNAN);
7303 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007304 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
7305 v = (*cur - '0');
7306 fraction = fraction * 10 + v;
7307 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007308 cur++;
7309 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007310 fraction /= my_pow10[frac];
7311 ret = ret + fraction;
7312 while ((*cur >= '0') && (*cur <= '9'))
7313 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007314 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007315 if ((*cur == 'e') || (*cur == 'E')) {
7316 cur++;
7317 if (*cur == '-') {
7318 is_exponent_negative = 1;
7319 cur++;
7320 }
7321 while ((*cur >= '0') && (*cur <= '9')) {
7322 exponent = exponent * 10 + (*cur - '0');
7323 cur++;
7324 }
7325 }
Owen Taylor3473f882001-02-23 17:55:21 +00007326 while (IS_BLANK(*cur)) cur++;
7327 if (*cur != 0) return(xmlXPathNAN);
7328 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007329 if (is_exponent_negative) exponent = -exponent;
7330 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007331 return(ret);
7332}
7333
7334/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007335 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007336 * @ctxt: the XPath Parser context
7337 *
7338 * [30] Number ::= Digits ('.' Digits?)?
7339 * | '.' Digits
7340 * [31] Digits ::= [0-9]+
7341 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007342 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007343 *
7344 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007345static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007346xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7347{
Owen Taylor3473f882001-02-23 17:55:21 +00007348 double ret = 0.0;
7349 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007350 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007351 int exponent = 0;
7352 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007353#ifdef __GNUC__
7354 unsigned long tmp = 0;
7355 double temp;
7356#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007357
7358 CHECK_ERROR;
7359 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7360 XP_ERROR(XPATH_NUMBER_ERROR);
7361 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007362#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007363 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007364 * tmp/temp is a workaround against a gcc compiler bug
7365 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007366 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007367 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007368 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007369 ret = ret * 10;
7370 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007371 ok = 1;
7372 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007373 temp = (double) tmp;
7374 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007375 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007376#else
7377 ret = 0;
7378 while ((CUR >= '0') && (CUR <= '9')) {
7379 ret = ret * 10 + (CUR - '0');
7380 ok = 1;
7381 NEXT;
7382 }
7383#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007384 if (CUR == '.') {
7385 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007386 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7387 XP_ERROR(XPATH_NUMBER_ERROR);
7388 }
7389 while ((CUR >= '0') && (CUR <= '9')) {
7390 mult /= 10;
7391 ret = ret + (CUR - '0') * mult;
7392 NEXT;
7393 }
Owen Taylor3473f882001-02-23 17:55:21 +00007394 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007395 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007396 NEXT;
7397 if (CUR == '-') {
7398 is_exponent_negative = 1;
7399 NEXT;
7400 }
7401 while ((CUR >= '0') && (CUR <= '9')) {
7402 exponent = exponent * 10 + (CUR - '0');
7403 NEXT;
7404 }
7405 if (is_exponent_negative)
7406 exponent = -exponent;
7407 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007408 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007409 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007410 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007411}
7412
7413/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007414 * xmlXPathParseLiteral:
7415 * @ctxt: the XPath Parser context
7416 *
7417 * Parse a Literal
7418 *
7419 * [29] Literal ::= '"' [^"]* '"'
7420 * | "'" [^']* "'"
7421 *
7422 * Returns the value found or NULL in case of error
7423 */
7424static xmlChar *
7425xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7426 const xmlChar *q;
7427 xmlChar *ret = NULL;
7428
7429 if (CUR == '"') {
7430 NEXT;
7431 q = CUR_PTR;
7432 while ((IS_CHAR(CUR)) && (CUR != '"'))
7433 NEXT;
7434 if (!IS_CHAR(CUR)) {
7435 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7436 } else {
7437 ret = xmlStrndup(q, CUR_PTR - q);
7438 NEXT;
7439 }
7440 } else if (CUR == '\'') {
7441 NEXT;
7442 q = CUR_PTR;
7443 while ((IS_CHAR(CUR)) && (CUR != '\''))
7444 NEXT;
7445 if (!IS_CHAR(CUR)) {
7446 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7447 } else {
7448 ret = xmlStrndup(q, CUR_PTR - q);
7449 NEXT;
7450 }
7451 } else {
7452 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7453 }
7454 return(ret);
7455}
7456
7457/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007458 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007459 * @ctxt: the XPath Parser context
7460 *
7461 * Parse a Literal and push it on the stack.
7462 *
7463 * [29] Literal ::= '"' [^"]* '"'
7464 * | "'" [^']* "'"
7465 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007466 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007467 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007468static void
7469xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007470 const xmlChar *q;
7471 xmlChar *ret = NULL;
7472
7473 if (CUR == '"') {
7474 NEXT;
7475 q = CUR_PTR;
7476 while ((IS_CHAR(CUR)) && (CUR != '"'))
7477 NEXT;
7478 if (!IS_CHAR(CUR)) {
7479 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7480 } else {
7481 ret = xmlStrndup(q, CUR_PTR - q);
7482 NEXT;
7483 }
7484 } else if (CUR == '\'') {
7485 NEXT;
7486 q = CUR_PTR;
7487 while ((IS_CHAR(CUR)) && (CUR != '\''))
7488 NEXT;
7489 if (!IS_CHAR(CUR)) {
7490 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7491 } else {
7492 ret = xmlStrndup(q, CUR_PTR - q);
7493 NEXT;
7494 }
7495 } else {
7496 XP_ERROR(XPATH_START_LITERAL_ERROR);
7497 }
7498 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007499 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7500 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007501 xmlFree(ret);
7502}
7503
7504/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007505 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007506 * @ctxt: the XPath Parser context
7507 *
7508 * Parse a VariableReference, evaluate it and push it on the stack.
7509 *
7510 * The variable bindings consist of a mapping from variable names
7511 * to variable values. The value of a variable is an object, which
7512 * of any of the types that are possible for the value of an expression,
7513 * and may also be of additional types not specified here.
7514 *
7515 * Early evaluation is possible since:
7516 * The variable bindings [...] used to evaluate a subexpression are
7517 * always the same as those used to evaluate the containing expression.
7518 *
7519 * [36] VariableReference ::= '$' QName
7520 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007521static void
7522xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007523 xmlChar *name;
7524 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007525
7526 SKIP_BLANKS;
7527 if (CUR != '$') {
7528 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7529 }
7530 NEXT;
7531 name = xmlXPathParseQName(ctxt, &prefix);
7532 if (name == NULL) {
7533 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7534 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007535 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007536 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7537 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007538 SKIP_BLANKS;
7539}
7540
7541/**
7542 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +00007543 * @name: a name string
7544 *
7545 * Is the name given a NodeType one.
7546 *
7547 * [38] NodeType ::= 'comment'
7548 * | 'text'
7549 * | 'processing-instruction'
7550 * | 'node'
7551 *
7552 * Returns 1 if true 0 otherwise
7553 */
7554int
7555xmlXPathIsNodeType(const xmlChar *name) {
7556 if (name == NULL)
7557 return(0);
7558
Daniel Veillard1971ee22002-01-31 20:29:19 +00007559 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007560 return(1);
7561 if (xmlStrEqual(name, BAD_CAST "text"))
7562 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007563 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007564 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007565 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007566 return(1);
7567 return(0);
7568}
7569
7570/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007571 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007572 * @ctxt: the XPath Parser context
7573 *
7574 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7575 * [17] Argument ::= Expr
7576 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007577 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007578 * pushed on the stack
7579 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007580static void
7581xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007582 xmlChar *name;
7583 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007584 int nbargs = 0;
7585
7586 name = xmlXPathParseQName(ctxt, &prefix);
7587 if (name == NULL) {
7588 XP_ERROR(XPATH_EXPR_ERROR);
7589 }
7590 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007591#ifdef DEBUG_EXPR
7592 if (prefix == NULL)
7593 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7594 name);
7595 else
7596 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7597 prefix, name);
7598#endif
7599
Owen Taylor3473f882001-02-23 17:55:21 +00007600 if (CUR != '(') {
7601 XP_ERROR(XPATH_EXPR_ERROR);
7602 }
7603 NEXT;
7604 SKIP_BLANKS;
7605
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007606 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007607 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007608 int op1 = ctxt->comp->last;
7609 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007610 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007611 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007612 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007613 nbargs++;
7614 if (CUR == ')') break;
7615 if (CUR != ',') {
7616 XP_ERROR(XPATH_EXPR_ERROR);
7617 }
7618 NEXT;
7619 SKIP_BLANKS;
7620 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007621 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7622 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007623 NEXT;
7624 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007625}
7626
7627/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007628 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007629 * @ctxt: the XPath Parser context
7630 *
7631 * [15] PrimaryExpr ::= VariableReference
7632 * | '(' Expr ')'
7633 * | Literal
7634 * | Number
7635 * | FunctionCall
7636 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007637 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007638 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007639static void
7640xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007641 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007642 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007643 else if (CUR == '(') {
7644 NEXT;
7645 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007646 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007647 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00007648 if (CUR != ')') {
7649 XP_ERROR(XPATH_EXPR_ERROR);
7650 }
7651 NEXT;
7652 SKIP_BLANKS;
Daniel Veillard01917aa2002-04-10 11:30:41 +00007653 } else if (IS_DIGIT(CUR) || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007654 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007655 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007656 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007657 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007658 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007659 }
7660 SKIP_BLANKS;
7661}
7662
7663/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007664 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007665 * @ctxt: the XPath Parser context
7666 *
7667 * [20] FilterExpr ::= PrimaryExpr
7668 * | FilterExpr Predicate
7669 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007670 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007671 * Square brackets are used to filter expressions in the same way that
7672 * they are used in location paths. It is an error if the expression to
7673 * be filtered does not evaluate to a node-set. The context node list
7674 * used for evaluating the expression in square brackets is the node-set
7675 * to be filtered listed in document order.
7676 */
7677
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007678static void
7679xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
7680 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007681 CHECK_ERROR;
7682 SKIP_BLANKS;
7683
7684 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007685 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00007686 SKIP_BLANKS;
7687 }
7688
7689
7690}
7691
7692/**
7693 * xmlXPathScanName:
7694 * @ctxt: the XPath Parser context
7695 *
7696 * Trickery: parse an XML name but without consuming the input flow
7697 * Needed to avoid insanity in the parser state.
7698 *
7699 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7700 * CombiningChar | Extender
7701 *
7702 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7703 *
7704 * [6] Names ::= Name (S Name)*
7705 *
7706 * Returns the Name parsed or NULL
7707 */
7708
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007709static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007710xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7711 xmlChar buf[XML_MAX_NAMELEN];
7712 int len = 0;
7713
7714 SKIP_BLANKS;
7715 if (!IS_LETTER(CUR) && (CUR != '_') &&
7716 (CUR != ':')) {
7717 return(NULL);
7718 }
7719
7720 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7721 (NXT(len) == '.') || (NXT(len) == '-') ||
7722 (NXT(len) == '_') || (NXT(len) == ':') ||
7723 (IS_COMBINING(NXT(len))) ||
7724 (IS_EXTENDER(NXT(len)))) {
7725 buf[len] = NXT(len);
7726 len++;
7727 if (len >= XML_MAX_NAMELEN) {
7728 xmlGenericError(xmlGenericErrorContext,
7729 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
7730 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7731 (NXT(len) == '.') || (NXT(len) == '-') ||
7732 (NXT(len) == '_') || (NXT(len) == ':') ||
7733 (IS_COMBINING(NXT(len))) ||
7734 (IS_EXTENDER(NXT(len))))
7735 len++;
7736 break;
7737 }
7738 }
7739 return(xmlStrndup(buf, len));
7740}
7741
7742/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007743 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007744 * @ctxt: the XPath Parser context
7745 *
7746 * [19] PathExpr ::= LocationPath
7747 * | FilterExpr
7748 * | FilterExpr '/' RelativeLocationPath
7749 * | FilterExpr '//' RelativeLocationPath
7750 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007751 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007752 * The / operator and // operators combine an arbitrary expression
7753 * and a relative location path. It is an error if the expression
7754 * does not evaluate to a node-set.
7755 * The / operator does composition in the same way as when / is
7756 * used in a location path. As in location paths, // is short for
7757 * /descendant-or-self::node()/.
7758 */
7759
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007760static void
7761xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007762 int lc = 1; /* Should we branch to LocationPath ? */
7763 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7764
7765 SKIP_BLANKS;
7766 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
Daniel Veillard01917aa2002-04-10 11:30:41 +00007767 (CUR == '\'') || (CUR == '"') || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00007768 lc = 0;
7769 } else if (CUR == '*') {
7770 /* relative or absolute location path */
7771 lc = 1;
7772 } else if (CUR == '/') {
7773 /* relative or absolute location path */
7774 lc = 1;
7775 } else if (CUR == '@') {
7776 /* relative abbreviated attribute location path */
7777 lc = 1;
7778 } else if (CUR == '.') {
7779 /* relative abbreviated attribute location path */
7780 lc = 1;
7781 } else {
7782 /*
7783 * Problem is finding if we have a name here whether it's:
7784 * - a nodetype
7785 * - a function call in which case it's followed by '('
7786 * - an axis in which case it's followed by ':'
7787 * - a element name
7788 * We do an a priori analysis here rather than having to
7789 * maintain parsed token content through the recursive function
7790 * calls. This looks uglier but makes the code quite easier to
7791 * read/write/debug.
7792 */
7793 SKIP_BLANKS;
7794 name = xmlXPathScanName(ctxt);
7795 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7796#ifdef DEBUG_STEP
7797 xmlGenericError(xmlGenericErrorContext,
7798 "PathExpr: Axis\n");
7799#endif
7800 lc = 1;
7801 xmlFree(name);
7802 } else if (name != NULL) {
7803 int len =xmlStrlen(name);
7804 int blank = 0;
7805
7806
7807 while (NXT(len) != 0) {
7808 if (NXT(len) == '/') {
7809 /* element name */
7810#ifdef DEBUG_STEP
7811 xmlGenericError(xmlGenericErrorContext,
7812 "PathExpr: AbbrRelLocation\n");
7813#endif
7814 lc = 1;
7815 break;
7816 } else if (IS_BLANK(NXT(len))) {
7817 /* skip to next */
7818 blank = 1;
7819 } else if (NXT(len) == ':') {
7820#ifdef DEBUG_STEP
7821 xmlGenericError(xmlGenericErrorContext,
7822 "PathExpr: AbbrRelLocation\n");
7823#endif
7824 lc = 1;
7825 break;
7826 } else if ((NXT(len) == '(')) {
7827 /* Note Type or Function */
7828 if (xmlXPathIsNodeType(name)) {
7829#ifdef DEBUG_STEP
7830 xmlGenericError(xmlGenericErrorContext,
7831 "PathExpr: Type search\n");
7832#endif
7833 lc = 1;
7834 } else {
7835#ifdef DEBUG_STEP
7836 xmlGenericError(xmlGenericErrorContext,
7837 "PathExpr: function call\n");
7838#endif
7839 lc = 0;
7840 }
7841 break;
7842 } else 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 ((NXT(len) == '<') || (NXT(len) == '>') ||
7851 (NXT(len) == '=')) {
7852 lc = 1;
7853 break;
7854 } else {
7855 lc = 1;
7856 break;
7857 }
7858 len++;
7859 }
7860 if (NXT(len) == 0) {
7861#ifdef DEBUG_STEP
7862 xmlGenericError(xmlGenericErrorContext,
7863 "PathExpr: AbbrRelLocation\n");
7864#endif
7865 /* element name */
7866 lc = 1;
7867 }
7868 xmlFree(name);
7869 } else {
7870 /* make sure all cases are covered explicitely */
7871 XP_ERROR(XPATH_EXPR_ERROR);
7872 }
7873 }
7874
7875 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007876 if (CUR == '/') {
7877 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
7878 } else {
7879 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007880 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007881 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007882 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007883 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007884 CHECK_ERROR;
7885 if ((CUR == '/') && (NXT(1) == '/')) {
7886 SKIP(2);
7887 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007888
7889 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7890 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
7891 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
7892
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007893 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007894 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007895 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007896 }
7897 }
7898 SKIP_BLANKS;
7899}
7900
7901/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007902 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007903 * @ctxt: the XPath Parser context
7904 *
7905 * [18] UnionExpr ::= PathExpr
7906 * | UnionExpr '|' PathExpr
7907 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007908 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007909 */
7910
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007911static void
7912xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
7913 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007914 CHECK_ERROR;
7915 SKIP_BLANKS;
7916 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007917 int op1 = ctxt->comp->last;
7918 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007919
7920 NEXT;
7921 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007922 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007923
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007924 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
7925
Owen Taylor3473f882001-02-23 17:55:21 +00007926 SKIP_BLANKS;
7927 }
Owen Taylor3473f882001-02-23 17:55:21 +00007928}
7929
7930/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007931 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007932 * @ctxt: the XPath Parser context
7933 *
7934 * [27] UnaryExpr ::= UnionExpr
7935 * | '-' UnaryExpr
7936 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007937 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007938 */
7939
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007940static void
7941xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007942 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007943 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007944
7945 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00007946 while (CUR == '-') {
7947 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007948 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007949 NEXT;
7950 SKIP_BLANKS;
7951 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007952
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007953 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007954 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007955 if (found) {
7956 if (minus)
7957 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
7958 else
7959 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007960 }
7961}
7962
7963/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007964 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007965 * @ctxt: the XPath Parser context
7966 *
7967 * [26] MultiplicativeExpr ::= UnaryExpr
7968 * | MultiplicativeExpr MultiplyOperator UnaryExpr
7969 * | MultiplicativeExpr 'div' UnaryExpr
7970 * | MultiplicativeExpr 'mod' UnaryExpr
7971 * [34] MultiplyOperator ::= '*'
7972 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007973 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007974 */
7975
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007976static void
7977xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
7978 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007979 CHECK_ERROR;
7980 SKIP_BLANKS;
7981 while ((CUR == '*') ||
7982 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
7983 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
7984 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007985 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007986
7987 if (CUR == '*') {
7988 op = 0;
7989 NEXT;
7990 } else if (CUR == 'd') {
7991 op = 1;
7992 SKIP(3);
7993 } else if (CUR == 'm') {
7994 op = 2;
7995 SKIP(3);
7996 }
7997 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007998 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007999 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008000 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008001 SKIP_BLANKS;
8002 }
8003}
8004
8005/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008006 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008007 * @ctxt: the XPath Parser context
8008 *
8009 * [25] AdditiveExpr ::= MultiplicativeExpr
8010 * | AdditiveExpr '+' MultiplicativeExpr
8011 * | AdditiveExpr '-' MultiplicativeExpr
8012 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008013 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008014 */
8015
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008016static void
8017xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008018
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008019 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008020 CHECK_ERROR;
8021 SKIP_BLANKS;
8022 while ((CUR == '+') || (CUR == '-')) {
8023 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008024 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008025
8026 if (CUR == '+') plus = 1;
8027 else plus = 0;
8028 NEXT;
8029 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008030 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008031 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008032 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008033 SKIP_BLANKS;
8034 }
8035}
8036
8037/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008038 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008039 * @ctxt: the XPath Parser context
8040 *
8041 * [24] RelationalExpr ::= AdditiveExpr
8042 * | RelationalExpr '<' AdditiveExpr
8043 * | RelationalExpr '>' AdditiveExpr
8044 * | RelationalExpr '<=' AdditiveExpr
8045 * | RelationalExpr '>=' AdditiveExpr
8046 *
8047 * A <= B > C is allowed ? Answer from James, yes with
8048 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8049 * which is basically what got implemented.
8050 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008051 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00008052 * on the stack
8053 */
8054
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008055static void
8056xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8057 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008058 CHECK_ERROR;
8059 SKIP_BLANKS;
8060 while ((CUR == '<') ||
8061 (CUR == '>') ||
8062 ((CUR == '<') && (NXT(1) == '=')) ||
8063 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008064 int inf, strict;
8065 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008066
8067 if (CUR == '<') inf = 1;
8068 else inf = 0;
8069 if (NXT(1) == '=') strict = 0;
8070 else strict = 1;
8071 NEXT;
8072 if (!strict) NEXT;
8073 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008074 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008075 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008076 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00008077 SKIP_BLANKS;
8078 }
8079}
8080
8081/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008082 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008083 * @ctxt: the XPath Parser context
8084 *
8085 * [23] EqualityExpr ::= RelationalExpr
8086 * | EqualityExpr '=' RelationalExpr
8087 * | EqualityExpr '!=' RelationalExpr
8088 *
8089 * A != B != C is allowed ? Answer from James, yes with
8090 * (RelationalExpr = RelationalExpr) = RelationalExpr
8091 * (RelationalExpr != RelationalExpr) != RelationalExpr
8092 * which is basically what got implemented.
8093 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008094 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008095 *
8096 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008097static void
8098xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8099 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008100 CHECK_ERROR;
8101 SKIP_BLANKS;
8102 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008103 int eq;
8104 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008105
8106 if (CUR == '=') eq = 1;
8107 else eq = 0;
8108 NEXT;
8109 if (!eq) NEXT;
8110 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008111 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008112 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008113 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008114 SKIP_BLANKS;
8115 }
8116}
8117
8118/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008119 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008120 * @ctxt: the XPath Parser context
8121 *
8122 * [22] AndExpr ::= EqualityExpr
8123 * | AndExpr 'and' EqualityExpr
8124 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008125 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008126 *
8127 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008128static void
8129xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8130 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008131 CHECK_ERROR;
8132 SKIP_BLANKS;
8133 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008134 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008135 SKIP(3);
8136 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008137 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008138 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008139 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008140 SKIP_BLANKS;
8141 }
8142}
8143
8144/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008145 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008146 * @ctxt: the XPath Parser context
8147 *
8148 * [14] Expr ::= OrExpr
8149 * [21] OrExpr ::= AndExpr
8150 * | OrExpr 'or' AndExpr
8151 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008152 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00008153 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008154static void
8155xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8156 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008157 CHECK_ERROR;
8158 SKIP_BLANKS;
8159 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008160 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008161 SKIP(2);
8162 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008163 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008164 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008165 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8166 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00008167 SKIP_BLANKS;
8168 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008169 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8170 /* more ops could be optimized too */
8171 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8172 }
Owen Taylor3473f882001-02-23 17:55:21 +00008173}
8174
8175/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008176 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00008177 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008178 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00008179 *
8180 * [8] Predicate ::= '[' PredicateExpr ']'
8181 * [9] PredicateExpr ::= Expr
8182 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008183 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008184 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008185static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008186xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008187 int op1 = ctxt->comp->last;
8188
8189 SKIP_BLANKS;
8190 if (CUR != '[') {
8191 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8192 }
8193 NEXT;
8194 SKIP_BLANKS;
8195
8196 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008197 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008198 CHECK_ERROR;
8199
8200 if (CUR != ']') {
8201 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8202 }
8203
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008204 if (filter)
8205 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8206 else
8207 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008208
8209 NEXT;
8210 SKIP_BLANKS;
8211}
8212
8213/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008214 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00008215 * @ctxt: the XPath Parser context
8216 * @test: pointer to a xmlXPathTestVal
8217 * @type: pointer to a xmlXPathTypeVal
8218 * @prefix: placeholder for a possible name prefix
8219 *
8220 * [7] NodeTest ::= NameTest
8221 * | NodeType '(' ')'
8222 * | 'processing-instruction' '(' Literal ')'
8223 *
8224 * [37] NameTest ::= '*'
8225 * | NCName ':' '*'
8226 * | QName
8227 * [38] NodeType ::= 'comment'
8228 * | 'text'
8229 * | 'processing-instruction'
8230 * | 'node'
8231 *
8232 * Returns the name found and update @test, @type and @prefix appropriately
8233 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008234static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008235xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8236 xmlXPathTypeVal *type, const xmlChar **prefix,
8237 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008238 int blanks;
8239
8240 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8241 STRANGE;
8242 return(NULL);
8243 }
8244 *type = 0;
8245 *test = 0;
8246 *prefix = NULL;
8247 SKIP_BLANKS;
8248
8249 if ((name == NULL) && (CUR == '*')) {
8250 /*
8251 * All elements
8252 */
8253 NEXT;
8254 *test = NODE_TEST_ALL;
8255 return(NULL);
8256 }
8257
8258 if (name == NULL)
8259 name = xmlXPathParseNCName(ctxt);
8260 if (name == NULL) {
8261 XP_ERROR0(XPATH_EXPR_ERROR);
8262 }
8263
8264 blanks = IS_BLANK(CUR);
8265 SKIP_BLANKS;
8266 if (CUR == '(') {
8267 NEXT;
8268 /*
8269 * NodeType or PI search
8270 */
8271 if (xmlStrEqual(name, BAD_CAST "comment"))
8272 *type = NODE_TYPE_COMMENT;
8273 else if (xmlStrEqual(name, BAD_CAST "node"))
8274 *type = NODE_TYPE_NODE;
8275 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8276 *type = NODE_TYPE_PI;
8277 else if (xmlStrEqual(name, BAD_CAST "text"))
8278 *type = NODE_TYPE_TEXT;
8279 else {
8280 if (name != NULL)
8281 xmlFree(name);
8282 XP_ERROR0(XPATH_EXPR_ERROR);
8283 }
8284
8285 *test = NODE_TEST_TYPE;
8286
8287 SKIP_BLANKS;
8288 if (*type == NODE_TYPE_PI) {
8289 /*
8290 * Specific case: search a PI by name.
8291 */
Owen Taylor3473f882001-02-23 17:55:21 +00008292 if (name != NULL)
8293 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008294 name = NULL;
8295 if (CUR != ')') {
8296 name = xmlXPathParseLiteral(ctxt);
8297 CHECK_ERROR 0;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00008298 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00008299 SKIP_BLANKS;
8300 }
Owen Taylor3473f882001-02-23 17:55:21 +00008301 }
8302 if (CUR != ')') {
8303 if (name != NULL)
8304 xmlFree(name);
8305 XP_ERROR0(XPATH_UNCLOSED_ERROR);
8306 }
8307 NEXT;
8308 return(name);
8309 }
8310 *test = NODE_TEST_NAME;
8311 if ((!blanks) && (CUR == ':')) {
8312 NEXT;
8313
8314 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008315 * Since currently the parser context don't have a
8316 * namespace list associated:
8317 * The namespace name for this prefix can be computed
8318 * only at evaluation time. The compilation is done
8319 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008320 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008321#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008322 *prefix = xmlXPathNsLookup(ctxt->context, name);
8323 if (name != NULL)
8324 xmlFree(name);
8325 if (*prefix == NULL) {
8326 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8327 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008328#else
8329 *prefix = name;
8330#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008331
8332 if (CUR == '*') {
8333 /*
8334 * All elements
8335 */
8336 NEXT;
8337 *test = NODE_TEST_ALL;
8338 return(NULL);
8339 }
8340
8341 name = xmlXPathParseNCName(ctxt);
8342 if (name == NULL) {
8343 XP_ERROR0(XPATH_EXPR_ERROR);
8344 }
8345 }
8346 return(name);
8347}
8348
8349/**
8350 * xmlXPathIsAxisName:
8351 * @name: a preparsed name token
8352 *
8353 * [6] AxisName ::= 'ancestor'
8354 * | 'ancestor-or-self'
8355 * | 'attribute'
8356 * | 'child'
8357 * | 'descendant'
8358 * | 'descendant-or-self'
8359 * | 'following'
8360 * | 'following-sibling'
8361 * | 'namespace'
8362 * | 'parent'
8363 * | 'preceding'
8364 * | 'preceding-sibling'
8365 * | 'self'
8366 *
8367 * Returns the axis or 0
8368 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008369static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008370xmlXPathIsAxisName(const xmlChar *name) {
8371 xmlXPathAxisVal ret = 0;
8372 switch (name[0]) {
8373 case 'a':
8374 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8375 ret = AXIS_ANCESTOR;
8376 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8377 ret = AXIS_ANCESTOR_OR_SELF;
8378 if (xmlStrEqual(name, BAD_CAST "attribute"))
8379 ret = AXIS_ATTRIBUTE;
8380 break;
8381 case 'c':
8382 if (xmlStrEqual(name, BAD_CAST "child"))
8383 ret = AXIS_CHILD;
8384 break;
8385 case 'd':
8386 if (xmlStrEqual(name, BAD_CAST "descendant"))
8387 ret = AXIS_DESCENDANT;
8388 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8389 ret = AXIS_DESCENDANT_OR_SELF;
8390 break;
8391 case 'f':
8392 if (xmlStrEqual(name, BAD_CAST "following"))
8393 ret = AXIS_FOLLOWING;
8394 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8395 ret = AXIS_FOLLOWING_SIBLING;
8396 break;
8397 case 'n':
8398 if (xmlStrEqual(name, BAD_CAST "namespace"))
8399 ret = AXIS_NAMESPACE;
8400 break;
8401 case 'p':
8402 if (xmlStrEqual(name, BAD_CAST "parent"))
8403 ret = AXIS_PARENT;
8404 if (xmlStrEqual(name, BAD_CAST "preceding"))
8405 ret = AXIS_PRECEDING;
8406 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8407 ret = AXIS_PRECEDING_SIBLING;
8408 break;
8409 case 's':
8410 if (xmlStrEqual(name, BAD_CAST "self"))
8411 ret = AXIS_SELF;
8412 break;
8413 }
8414 return(ret);
8415}
8416
8417/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008418 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008419 * @ctxt: the XPath Parser context
8420 *
8421 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8422 * | AbbreviatedStep
8423 *
8424 * [12] AbbreviatedStep ::= '.' | '..'
8425 *
8426 * [5] AxisSpecifier ::= AxisName '::'
8427 * | AbbreviatedAxisSpecifier
8428 *
8429 * [13] AbbreviatedAxisSpecifier ::= '@'?
8430 *
8431 * Modified for XPtr range support as:
8432 *
8433 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8434 * | AbbreviatedStep
8435 * | 'range-to' '(' Expr ')' Predicate*
8436 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008437 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008438 * A location step of . is short for self::node(). This is
8439 * particularly useful in conjunction with //. For example, the
8440 * location path .//para is short for
8441 * self::node()/descendant-or-self::node()/child::para
8442 * and so will select all para descendant elements of the context
8443 * node.
8444 * Similarly, a location step of .. is short for parent::node().
8445 * For example, ../title is short for parent::node()/child::title
8446 * and so will select the title children of the parent of the context
8447 * node.
8448 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008449static void
8450xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008451#ifdef LIBXML_XPTR_ENABLED
8452 int rangeto = 0;
8453 int op2 = -1;
8454#endif
8455
Owen Taylor3473f882001-02-23 17:55:21 +00008456 SKIP_BLANKS;
8457 if ((CUR == '.') && (NXT(1) == '.')) {
8458 SKIP(2);
8459 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008460 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8461 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008462 } else if (CUR == '.') {
8463 NEXT;
8464 SKIP_BLANKS;
8465 } else {
8466 xmlChar *name = NULL;
8467 const xmlChar *prefix = NULL;
8468 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008469 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008470 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008471 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008472
8473 /*
8474 * The modification needed for XPointer change to the production
8475 */
8476#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008477 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008478 name = xmlXPathParseNCName(ctxt);
8479 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008480 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008481 xmlFree(name);
8482 SKIP_BLANKS;
8483 if (CUR != '(') {
8484 XP_ERROR(XPATH_EXPR_ERROR);
8485 }
8486 NEXT;
8487 SKIP_BLANKS;
8488
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008489 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008490 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008491 CHECK_ERROR;
8492
8493 SKIP_BLANKS;
8494 if (CUR != ')') {
8495 XP_ERROR(XPATH_EXPR_ERROR);
8496 }
8497 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008498 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008499 goto eval_predicates;
8500 }
8501 }
8502#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008503 if (CUR == '*') {
8504 axis = AXIS_CHILD;
8505 } else {
8506 if (name == NULL)
8507 name = xmlXPathParseNCName(ctxt);
8508 if (name != NULL) {
8509 axis = xmlXPathIsAxisName(name);
8510 if (axis != 0) {
8511 SKIP_BLANKS;
8512 if ((CUR == ':') && (NXT(1) == ':')) {
8513 SKIP(2);
8514 xmlFree(name);
8515 name = NULL;
8516 } else {
8517 /* an element name can conflict with an axis one :-\ */
8518 axis = AXIS_CHILD;
8519 }
Owen Taylor3473f882001-02-23 17:55:21 +00008520 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008521 axis = AXIS_CHILD;
8522 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008523 } else if (CUR == '@') {
8524 NEXT;
8525 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008526 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008527 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008528 }
Owen Taylor3473f882001-02-23 17:55:21 +00008529 }
8530
8531 CHECK_ERROR;
8532
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008533 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008534 if (test == 0)
8535 return;
8536
8537#ifdef DEBUG_STEP
8538 xmlGenericError(xmlGenericErrorContext,
8539 "Basis : computing new set\n");
8540#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008541
Owen Taylor3473f882001-02-23 17:55:21 +00008542#ifdef DEBUG_STEP
8543 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008544 if (ctxt->value == NULL)
8545 xmlGenericError(xmlGenericErrorContext, "no value\n");
8546 else if (ctxt->value->nodesetval == NULL)
8547 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8548 else
8549 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008550#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008551
8552eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008553 op1 = ctxt->comp->last;
8554 ctxt->comp->last = -1;
8555
Owen Taylor3473f882001-02-23 17:55:21 +00008556 SKIP_BLANKS;
8557 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008558 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008559 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008560
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008561#ifdef LIBXML_XPTR_ENABLED
8562 if (rangeto) {
8563 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8564 } else
8565#endif
8566 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8567 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008568
Owen Taylor3473f882001-02-23 17:55:21 +00008569 }
8570#ifdef DEBUG_STEP
8571 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008572 if (ctxt->value == NULL)
8573 xmlGenericError(xmlGenericErrorContext, "no value\n");
8574 else if (ctxt->value->nodesetval == NULL)
8575 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8576 else
8577 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8578 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008579#endif
8580}
8581
8582/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008583 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008584 * @ctxt: the XPath Parser context
8585 *
8586 * [3] RelativeLocationPath ::= Step
8587 * | RelativeLocationPath '/' Step
8588 * | AbbreviatedRelativeLocationPath
8589 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8590 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008591 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008592 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008593static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008594xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008595(xmlXPathParserContextPtr ctxt) {
8596 SKIP_BLANKS;
8597 if ((CUR == '/') && (NXT(1) == '/')) {
8598 SKIP(2);
8599 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008600 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8601 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008602 } else if (CUR == '/') {
8603 NEXT;
8604 SKIP_BLANKS;
8605 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008606 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008607 SKIP_BLANKS;
8608 while (CUR == '/') {
8609 if ((CUR == '/') && (NXT(1) == '/')) {
8610 SKIP(2);
8611 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008612 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008613 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008614 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008615 } else if (CUR == '/') {
8616 NEXT;
8617 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008618 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008619 }
8620 SKIP_BLANKS;
8621 }
8622}
8623
8624/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008625 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008626 * @ctxt: the XPath Parser context
8627 *
8628 * [1] LocationPath ::= RelativeLocationPath
8629 * | AbsoluteLocationPath
8630 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8631 * | AbbreviatedAbsoluteLocationPath
8632 * [10] AbbreviatedAbsoluteLocationPath ::=
8633 * '//' RelativeLocationPath
8634 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008635 * Compile a location path
8636 *
Owen Taylor3473f882001-02-23 17:55:21 +00008637 * // is short for /descendant-or-self::node()/. For example,
8638 * //para is short for /descendant-or-self::node()/child::para and
8639 * so will select any para element in the document (even a para element
8640 * that is a document element will be selected by //para since the
8641 * document element node is a child of the root node); div//para is
8642 * short for div/descendant-or-self::node()/child::para and so will
8643 * select all para descendants of div children.
8644 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008645static void
8646xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008647 SKIP_BLANKS;
8648 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008649 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008650 } else {
8651 while (CUR == '/') {
8652 if ((CUR == '/') && (NXT(1) == '/')) {
8653 SKIP(2);
8654 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008655 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8656 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008657 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008658 } else if (CUR == '/') {
8659 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008660 SKIP_BLANKS;
8661 if ((CUR != 0 ) &&
8662 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
8663 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008664 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008665 }
8666 }
8667 }
8668}
8669
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008670/************************************************************************
8671 * *
8672 * XPath precompiled expression evaluation *
8673 * *
8674 ************************************************************************/
8675
Daniel Veillardf06307e2001-07-03 10:35:50 +00008676static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008677xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8678
8679/**
8680 * xmlXPathNodeCollectAndTest:
8681 * @ctxt: the XPath Parser context
8682 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008683 * @first: pointer to the first element in document order
8684 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008685 *
8686 * This is the function implementing a step: based on the current list
8687 * of nodes, it builds up a new list, looking at all nodes under that
8688 * axis and selecting them it also do the predicate filtering
8689 *
8690 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00008691 *
8692 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008693 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008694static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008695xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008696 xmlXPathStepOpPtr op,
8697 xmlNodePtr * first, xmlNodePtr * last)
8698{
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008699 xmlXPathAxisVal axis = op->value;
8700 xmlXPathTestVal test = op->value2;
8701 xmlXPathTypeVal type = op->value3;
8702 const xmlChar *prefix = op->value4;
8703 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008704 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008705
8706#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008707 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008708#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008709 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008710 xmlNodeSetPtr ret, list;
8711 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008712 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00008713 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008714 xmlNodePtr cur = NULL;
8715 xmlXPathObjectPtr obj;
8716 xmlNodeSetPtr nodelist;
8717 xmlNodePtr tmp;
8718
Daniel Veillardf06307e2001-07-03 10:35:50 +00008719 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008720 obj = valuePop(ctxt);
8721 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00008722 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008723 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008724 URI = xmlXPathNsLookup(ctxt->context, prefix);
8725 if (URI == NULL)
8726 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008727 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008728#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008729 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008730#endif
8731 switch (axis) {
8732 case AXIS_ANCESTOR:
8733#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008734 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008735#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008736 first = NULL;
8737 next = xmlXPathNextAncestor;
8738 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008739 case AXIS_ANCESTOR_OR_SELF:
8740#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008741 xmlGenericError(xmlGenericErrorContext,
8742 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008743#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008744 first = NULL;
8745 next = xmlXPathNextAncestorOrSelf;
8746 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008747 case AXIS_ATTRIBUTE:
8748#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008749 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008750#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008751 first = NULL;
8752 last = NULL;
8753 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00008754 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008755 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008756 case AXIS_CHILD:
8757#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008758 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008759#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008760 last = NULL;
8761 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00008762 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008763 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008764 case AXIS_DESCENDANT:
8765#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008766 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008767#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008768 last = NULL;
8769 next = xmlXPathNextDescendant;
8770 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008771 case AXIS_DESCENDANT_OR_SELF:
8772#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008773 xmlGenericError(xmlGenericErrorContext,
8774 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008775#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008776 last = NULL;
8777 next = xmlXPathNextDescendantOrSelf;
8778 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008779 case AXIS_FOLLOWING:
8780#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008781 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008782#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008783 last = NULL;
8784 next = xmlXPathNextFollowing;
8785 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008786 case AXIS_FOLLOWING_SIBLING:
8787#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008788 xmlGenericError(xmlGenericErrorContext,
8789 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008790#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008791 last = NULL;
8792 next = xmlXPathNextFollowingSibling;
8793 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008794 case AXIS_NAMESPACE:
8795#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008796 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008797#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008798 first = NULL;
8799 last = NULL;
8800 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00008801 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008802 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008803 case AXIS_PARENT:
8804#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008805 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008806#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008807 first = NULL;
8808 next = xmlXPathNextParent;
8809 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008810 case AXIS_PRECEDING:
8811#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008812 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008813#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008814 first = NULL;
8815 next = xmlXPathNextPrecedingInternal;
8816 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008817 case AXIS_PRECEDING_SIBLING:
8818#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008819 xmlGenericError(xmlGenericErrorContext,
8820 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008821#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008822 first = NULL;
8823 next = xmlXPathNextPrecedingSibling;
8824 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008825 case AXIS_SELF:
8826#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008827 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008828#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008829 first = NULL;
8830 last = NULL;
8831 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00008832 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008833 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008834 }
8835 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008836 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008837
8838 nodelist = obj->nodesetval;
8839 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008840 xmlXPathFreeObject(obj);
8841 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8842 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008843 }
8844 addNode = xmlXPathNodeSetAddUnique;
8845 ret = NULL;
8846#ifdef DEBUG_STEP
8847 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008848 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008849 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008850 case NODE_TEST_NONE:
8851 xmlGenericError(xmlGenericErrorContext,
8852 " searching for none !!!\n");
8853 break;
8854 case NODE_TEST_TYPE:
8855 xmlGenericError(xmlGenericErrorContext,
8856 " searching for type %d\n", type);
8857 break;
8858 case NODE_TEST_PI:
8859 xmlGenericError(xmlGenericErrorContext,
8860 " searching for PI !!!\n");
8861 break;
8862 case NODE_TEST_ALL:
8863 xmlGenericError(xmlGenericErrorContext,
8864 " searching for *\n");
8865 break;
8866 case NODE_TEST_NS:
8867 xmlGenericError(xmlGenericErrorContext,
8868 " searching for namespace %s\n",
8869 prefix);
8870 break;
8871 case NODE_TEST_NAME:
8872 xmlGenericError(xmlGenericErrorContext,
8873 " searching for name %s\n", name);
8874 if (prefix != NULL)
8875 xmlGenericError(xmlGenericErrorContext,
8876 " with namespace %s\n", prefix);
8877 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008878 }
8879 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8880#endif
8881 /*
8882 * 2.3 Node Tests
8883 * - For the attribute axis, the principal node type is attribute.
8884 * - For the namespace axis, the principal node type is namespace.
8885 * - For other axes, the principal node type is element.
8886 *
8887 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008888 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008889 * select all element children of the context node
8890 */
8891 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008892 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008893 ctxt->context->node = nodelist->nodeTab[i];
8894
Daniel Veillardf06307e2001-07-03 10:35:50 +00008895 cur = NULL;
8896 list = xmlXPathNodeSetCreate(NULL);
8897 do {
8898 cur = next(ctxt, cur);
8899 if (cur == NULL)
8900 break;
8901 if ((first != NULL) && (*first == cur))
8902 break;
8903 if (((t % 256) == 0) &&
8904 (first != NULL) && (*first != NULL) &&
8905 (xmlXPathCmpNodes(*first, cur) >= 0))
8906 break;
8907 if ((last != NULL) && (*last == cur))
8908 break;
8909 if (((t % 256) == 0) &&
8910 (last != NULL) && (*last != NULL) &&
8911 (xmlXPathCmpNodes(cur, *last) >= 0))
8912 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008913 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008914#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008915 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
8916#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008917 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008918 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008919 ctxt->context->node = tmp;
8920 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008921 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008922 if ((cur->type == type) ||
8923 ((type == NODE_TYPE_NODE) &&
8924 ((cur->type == XML_DOCUMENT_NODE) ||
8925 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8926 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00008927 (cur->type == XML_NAMESPACE_DECL) ||
8928 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00008929 (cur->type == XML_PI_NODE) ||
8930 (cur->type == XML_COMMENT_NODE) ||
8931 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00008932 (cur->type == XML_TEXT_NODE))) ||
8933 ((type == NODE_TYPE_TEXT) &&
8934 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008935#ifdef DEBUG_STEP
8936 n++;
8937#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008938 addNode(list, cur);
8939 }
8940 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008941 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008942 if (cur->type == XML_PI_NODE) {
8943 if ((name != NULL) &&
8944 (!xmlStrEqual(name, cur->name)))
8945 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008946#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008947 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008948#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008949 addNode(list, cur);
8950 }
8951 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008952 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008953 if (axis == AXIS_ATTRIBUTE) {
8954 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008955#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008956 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008957#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008958 addNode(list, cur);
8959 }
8960 } else if (axis == AXIS_NAMESPACE) {
8961 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008962#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008963 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008964#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008965 xmlXPathNodeSetAddNs(list, ctxt->context->node,
8966 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008967 }
8968 } else {
8969 if (cur->type == XML_ELEMENT_NODE) {
8970 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008971#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008972 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008973#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008974 addNode(list, cur);
8975 } else if ((cur->ns != NULL) &&
8976 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008977#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008978 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008979#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008980 addNode(list, cur);
8981 }
8982 }
8983 }
8984 break;
8985 case NODE_TEST_NS:{
8986 TODO;
8987 break;
8988 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008989 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008990 switch (cur->type) {
8991 case XML_ELEMENT_NODE:
8992 if (xmlStrEqual(name, cur->name)) {
8993 if (prefix == NULL) {
8994 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008995#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008996 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008997#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008998 addNode(list, cur);
8999 }
9000 } else {
9001 if ((cur->ns != NULL) &&
9002 (xmlStrEqual(URI,
9003 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009004#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009005 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009006#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009007 addNode(list, cur);
9008 }
9009 }
9010 }
9011 break;
9012 case XML_ATTRIBUTE_NODE:{
9013 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009014
Daniel Veillardf06307e2001-07-03 10:35:50 +00009015 if (xmlStrEqual(name, attr->name)) {
9016 if (prefix == NULL) {
9017 if ((attr->ns == NULL) ||
9018 (attr->ns->prefix == NULL)) {
9019#ifdef DEBUG_STEP
9020 n++;
9021#endif
9022 addNode(list,
9023 (xmlNodePtr) attr);
9024 }
9025 } else {
9026 if ((attr->ns != NULL) &&
9027 (xmlStrEqual(URI,
9028 attr->ns->
9029 href))) {
9030#ifdef DEBUG_STEP
9031 n++;
9032#endif
9033 addNode(list,
9034 (xmlNodePtr) attr);
9035 }
9036 }
9037 }
9038 break;
9039 }
9040 case XML_NAMESPACE_DECL:
9041 if (cur->type == XML_NAMESPACE_DECL) {
9042 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009043
Daniel Veillardf06307e2001-07-03 10:35:50 +00009044 if ((ns->prefix != NULL) && (name != NULL)
9045 && (xmlStrEqual(ns->prefix, name))) {
9046#ifdef DEBUG_STEP
9047 n++;
9048#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009049 xmlXPathNodeSetAddNs(list,
9050 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009051 }
9052 }
9053 break;
9054 default:
9055 break;
9056 }
9057 break;
9058 break;
9059 }
9060 } while (cur != NULL);
9061
9062 /*
9063 * If there is some predicate filtering do it now
9064 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009065 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009066 xmlXPathObjectPtr obj2;
9067
9068 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9069 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9070 CHECK_TYPE0(XPATH_NODESET);
9071 obj2 = valuePop(ctxt);
9072 list = obj2->nodesetval;
9073 obj2->nodesetval = NULL;
9074 xmlXPathFreeObject(obj2);
9075 }
9076 if (ret == NULL) {
9077 ret = list;
9078 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009079 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009080 xmlXPathFreeNodeSet(list);
9081 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009082 }
9083 ctxt->context->node = tmp;
9084#ifdef DEBUG_STEP
9085 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009086 "\nExamined %d nodes, found %d nodes at that step\n",
9087 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009088#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009089 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009090 if ((obj->boolval) && (obj->user != NULL)) {
9091 ctxt->value->boolval = 1;
9092 ctxt->value->user = obj->user;
9093 obj->user = NULL;
9094 obj->boolval = 0;
9095 }
9096 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009097 return(t);
9098}
9099
9100/**
9101 * xmlXPathNodeCollectAndTestNth:
9102 * @ctxt: the XPath Parser context
9103 * @op: the XPath precompiled step operation
9104 * @indx: the index to collect
9105 * @first: pointer to the first element in document order
9106 * @last: pointer to the last element in document order
9107 *
9108 * This is the function implementing a step: based on the current list
9109 * of nodes, it builds up a new list, looking at all nodes under that
9110 * axis and selecting them it also do the predicate filtering
9111 *
9112 * Pushes the new NodeSet resulting from the search.
9113 * Returns the number of node traversed
9114 */
9115static int
9116xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9117 xmlXPathStepOpPtr op, int indx,
9118 xmlNodePtr * first, xmlNodePtr * last)
9119{
9120 xmlXPathAxisVal axis = op->value;
9121 xmlXPathTestVal test = op->value2;
9122 xmlXPathTypeVal type = op->value3;
9123 const xmlChar *prefix = op->value4;
9124 const xmlChar *name = op->value5;
9125 const xmlChar *URI = NULL;
9126 int n = 0, t = 0;
9127
9128 int i;
9129 xmlNodeSetPtr list;
9130 xmlXPathTraversalFunction next = NULL;
9131 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9132 xmlNodePtr cur = NULL;
9133 xmlXPathObjectPtr obj;
9134 xmlNodeSetPtr nodelist;
9135 xmlNodePtr tmp;
9136
9137 CHECK_TYPE0(XPATH_NODESET);
9138 obj = valuePop(ctxt);
9139 addNode = xmlXPathNodeSetAdd;
9140 if (prefix != NULL) {
9141 URI = xmlXPathNsLookup(ctxt->context, prefix);
9142 if (URI == NULL)
9143 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9144 }
9145#ifdef DEBUG_STEP_NTH
9146 xmlGenericError(xmlGenericErrorContext, "new step : ");
9147 if (first != NULL) {
9148 if (*first != NULL)
9149 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9150 (*first)->name);
9151 else
9152 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9153 }
9154 if (last != NULL) {
9155 if (*last != NULL)
9156 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9157 (*last)->name);
9158 else
9159 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9160 }
9161#endif
9162 switch (axis) {
9163 case AXIS_ANCESTOR:
9164#ifdef DEBUG_STEP_NTH
9165 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9166#endif
9167 first = NULL;
9168 next = xmlXPathNextAncestor;
9169 break;
9170 case AXIS_ANCESTOR_OR_SELF:
9171#ifdef DEBUG_STEP_NTH
9172 xmlGenericError(xmlGenericErrorContext,
9173 "axis 'ancestors-or-self' ");
9174#endif
9175 first = NULL;
9176 next = xmlXPathNextAncestorOrSelf;
9177 break;
9178 case AXIS_ATTRIBUTE:
9179#ifdef DEBUG_STEP_NTH
9180 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9181#endif
9182 first = NULL;
9183 last = NULL;
9184 next = xmlXPathNextAttribute;
9185 break;
9186 case AXIS_CHILD:
9187#ifdef DEBUG_STEP_NTH
9188 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9189#endif
9190 last = NULL;
9191 next = xmlXPathNextChild;
9192 break;
9193 case AXIS_DESCENDANT:
9194#ifdef DEBUG_STEP_NTH
9195 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9196#endif
9197 last = NULL;
9198 next = xmlXPathNextDescendant;
9199 break;
9200 case AXIS_DESCENDANT_OR_SELF:
9201#ifdef DEBUG_STEP_NTH
9202 xmlGenericError(xmlGenericErrorContext,
9203 "axis 'descendant-or-self' ");
9204#endif
9205 last = NULL;
9206 next = xmlXPathNextDescendantOrSelf;
9207 break;
9208 case AXIS_FOLLOWING:
9209#ifdef DEBUG_STEP_NTH
9210 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9211#endif
9212 last = NULL;
9213 next = xmlXPathNextFollowing;
9214 break;
9215 case AXIS_FOLLOWING_SIBLING:
9216#ifdef DEBUG_STEP_NTH
9217 xmlGenericError(xmlGenericErrorContext,
9218 "axis 'following-siblings' ");
9219#endif
9220 last = NULL;
9221 next = xmlXPathNextFollowingSibling;
9222 break;
9223 case AXIS_NAMESPACE:
9224#ifdef DEBUG_STEP_NTH
9225 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9226#endif
9227 last = NULL;
9228 first = NULL;
9229 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9230 break;
9231 case AXIS_PARENT:
9232#ifdef DEBUG_STEP_NTH
9233 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9234#endif
9235 first = NULL;
9236 next = xmlXPathNextParent;
9237 break;
9238 case AXIS_PRECEDING:
9239#ifdef DEBUG_STEP_NTH
9240 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9241#endif
9242 first = NULL;
9243 next = xmlXPathNextPrecedingInternal;
9244 break;
9245 case AXIS_PRECEDING_SIBLING:
9246#ifdef DEBUG_STEP_NTH
9247 xmlGenericError(xmlGenericErrorContext,
9248 "axis 'preceding-sibling' ");
9249#endif
9250 first = NULL;
9251 next = xmlXPathNextPrecedingSibling;
9252 break;
9253 case AXIS_SELF:
9254#ifdef DEBUG_STEP_NTH
9255 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9256#endif
9257 first = NULL;
9258 last = NULL;
9259 next = xmlXPathNextSelf;
9260 break;
9261 }
9262 if (next == NULL)
9263 return(0);
9264
9265 nodelist = obj->nodesetval;
9266 if (nodelist == NULL) {
9267 xmlXPathFreeObject(obj);
9268 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9269 return(0);
9270 }
9271 addNode = xmlXPathNodeSetAddUnique;
9272#ifdef DEBUG_STEP_NTH
9273 xmlGenericError(xmlGenericErrorContext,
9274 " context contains %d nodes\n", nodelist->nodeNr);
9275 switch (test) {
9276 case NODE_TEST_NONE:
9277 xmlGenericError(xmlGenericErrorContext,
9278 " searching for none !!!\n");
9279 break;
9280 case NODE_TEST_TYPE:
9281 xmlGenericError(xmlGenericErrorContext,
9282 " searching for type %d\n", type);
9283 break;
9284 case NODE_TEST_PI:
9285 xmlGenericError(xmlGenericErrorContext,
9286 " searching for PI !!!\n");
9287 break;
9288 case NODE_TEST_ALL:
9289 xmlGenericError(xmlGenericErrorContext,
9290 " searching for *\n");
9291 break;
9292 case NODE_TEST_NS:
9293 xmlGenericError(xmlGenericErrorContext,
9294 " searching for namespace %s\n",
9295 prefix);
9296 break;
9297 case NODE_TEST_NAME:
9298 xmlGenericError(xmlGenericErrorContext,
9299 " searching for name %s\n", name);
9300 if (prefix != NULL)
9301 xmlGenericError(xmlGenericErrorContext,
9302 " with namespace %s\n", prefix);
9303 break;
9304 }
9305 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9306#endif
9307 /*
9308 * 2.3 Node Tests
9309 * - For the attribute axis, the principal node type is attribute.
9310 * - For the namespace axis, the principal node type is namespace.
9311 * - For other axes, the principal node type is element.
9312 *
9313 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009314 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009315 * select all element children of the context node
9316 */
9317 tmp = ctxt->context->node;
9318 list = xmlXPathNodeSetCreate(NULL);
9319 for (i = 0; i < nodelist->nodeNr; i++) {
9320 ctxt->context->node = nodelist->nodeTab[i];
9321
9322 cur = NULL;
9323 n = 0;
9324 do {
9325 cur = next(ctxt, cur);
9326 if (cur == NULL)
9327 break;
9328 if ((first != NULL) && (*first == cur))
9329 break;
9330 if (((t % 256) == 0) &&
9331 (first != NULL) && (*first != NULL) &&
9332 (xmlXPathCmpNodes(*first, cur) >= 0))
9333 break;
9334 if ((last != NULL) && (*last == cur))
9335 break;
9336 if (((t % 256) == 0) &&
9337 (last != NULL) && (*last != NULL) &&
9338 (xmlXPathCmpNodes(cur, *last) >= 0))
9339 break;
9340 t++;
9341 switch (test) {
9342 case NODE_TEST_NONE:
9343 ctxt->context->node = tmp;
9344 STRANGE return(0);
9345 case NODE_TEST_TYPE:
9346 if ((cur->type == type) ||
9347 ((type == NODE_TYPE_NODE) &&
9348 ((cur->type == XML_DOCUMENT_NODE) ||
9349 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9350 (cur->type == XML_ELEMENT_NODE) ||
9351 (cur->type == XML_PI_NODE) ||
9352 (cur->type == XML_COMMENT_NODE) ||
9353 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +00009354 (cur->type == XML_TEXT_NODE))) ||
9355 ((type == NODE_TYPE_TEXT) &&
9356 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009357 n++;
9358 if (n == indx)
9359 addNode(list, cur);
9360 }
9361 break;
9362 case NODE_TEST_PI:
9363 if (cur->type == XML_PI_NODE) {
9364 if ((name != NULL) &&
9365 (!xmlStrEqual(name, cur->name)))
9366 break;
9367 n++;
9368 if (n == indx)
9369 addNode(list, cur);
9370 }
9371 break;
9372 case NODE_TEST_ALL:
9373 if (axis == AXIS_ATTRIBUTE) {
9374 if (cur->type == XML_ATTRIBUTE_NODE) {
9375 n++;
9376 if (n == indx)
9377 addNode(list, cur);
9378 }
9379 } else if (axis == AXIS_NAMESPACE) {
9380 if (cur->type == XML_NAMESPACE_DECL) {
9381 n++;
9382 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009383 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9384 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009385 }
9386 } else {
9387 if (cur->type == XML_ELEMENT_NODE) {
9388 if (prefix == NULL) {
9389 n++;
9390 if (n == indx)
9391 addNode(list, cur);
9392 } else if ((cur->ns != NULL) &&
9393 (xmlStrEqual(URI, cur->ns->href))) {
9394 n++;
9395 if (n == indx)
9396 addNode(list, cur);
9397 }
9398 }
9399 }
9400 break;
9401 case NODE_TEST_NS:{
9402 TODO;
9403 break;
9404 }
9405 case NODE_TEST_NAME:
9406 switch (cur->type) {
9407 case XML_ELEMENT_NODE:
9408 if (xmlStrEqual(name, cur->name)) {
9409 if (prefix == NULL) {
9410 if (cur->ns == NULL) {
9411 n++;
9412 if (n == indx)
9413 addNode(list, cur);
9414 }
9415 } else {
9416 if ((cur->ns != NULL) &&
9417 (xmlStrEqual(URI,
9418 cur->ns->href))) {
9419 n++;
9420 if (n == indx)
9421 addNode(list, cur);
9422 }
9423 }
9424 }
9425 break;
9426 case XML_ATTRIBUTE_NODE:{
9427 xmlAttrPtr attr = (xmlAttrPtr) cur;
9428
9429 if (xmlStrEqual(name, attr->name)) {
9430 if (prefix == NULL) {
9431 if ((attr->ns == NULL) ||
9432 (attr->ns->prefix == NULL)) {
9433 n++;
9434 if (n == indx)
9435 addNode(list, cur);
9436 }
9437 } else {
9438 if ((attr->ns != NULL) &&
9439 (xmlStrEqual(URI,
9440 attr->ns->
9441 href))) {
9442 n++;
9443 if (n == indx)
9444 addNode(list, cur);
9445 }
9446 }
9447 }
9448 break;
9449 }
9450 case XML_NAMESPACE_DECL:
9451 if (cur->type == XML_NAMESPACE_DECL) {
9452 xmlNsPtr ns = (xmlNsPtr) cur;
9453
9454 if ((ns->prefix != NULL) && (name != NULL)
9455 && (xmlStrEqual(ns->prefix, name))) {
9456 n++;
9457 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009458 xmlXPathNodeSetAddNs(list,
9459 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009460 }
9461 }
9462 break;
9463 default:
9464 break;
9465 }
9466 break;
9467 break;
9468 }
9469 } while (n < indx);
9470 }
9471 ctxt->context->node = tmp;
9472#ifdef DEBUG_STEP_NTH
9473 xmlGenericError(xmlGenericErrorContext,
9474 "\nExamined %d nodes, found %d nodes at that step\n",
9475 t, list->nodeNr);
9476#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009477 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009478 if ((obj->boolval) && (obj->user != NULL)) {
9479 ctxt->value->boolval = 1;
9480 ctxt->value->user = obj->user;
9481 obj->user = NULL;
9482 obj->boolval = 0;
9483 }
9484 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009485 return(t);
9486}
9487
9488/**
9489 * xmlXPathCompOpEvalFirst:
9490 * @ctxt: the XPath parser context with the compiled expression
9491 * @op: an XPath compiled operation
9492 * @first: the first elem found so far
9493 *
9494 * Evaluate the Precompiled XPath operation searching only the first
9495 * element in document order
9496 *
9497 * Returns the number of examined objects.
9498 */
9499static int
9500xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9501 xmlXPathStepOpPtr op, xmlNodePtr * first)
9502{
9503 int total = 0, cur;
9504 xmlXPathCompExprPtr comp;
9505 xmlXPathObjectPtr arg1, arg2;
9506
Daniel Veillard556c6682001-10-06 09:59:51 +00009507 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009508 comp = ctxt->comp;
9509 switch (op->op) {
9510 case XPATH_OP_END:
9511 return (0);
9512 case XPATH_OP_UNION:
9513 total =
9514 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9515 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009516 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009517 if ((ctxt->value != NULL)
9518 && (ctxt->value->type == XPATH_NODESET)
9519 && (ctxt->value->nodesetval != NULL)
9520 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9521 /*
9522 * limit tree traversing to first node in the result
9523 */
9524 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9525 *first = ctxt->value->nodesetval->nodeTab[0];
9526 }
9527 cur =
9528 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9529 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009530 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009531 CHECK_TYPE0(XPATH_NODESET);
9532 arg2 = valuePop(ctxt);
9533
9534 CHECK_TYPE0(XPATH_NODESET);
9535 arg1 = valuePop(ctxt);
9536
9537 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9538 arg2->nodesetval);
9539 valuePush(ctxt, arg1);
9540 xmlXPathFreeObject(arg2);
9541 /* optimizer */
9542 if (total > cur)
9543 xmlXPathCompSwap(op);
9544 return (total + cur);
9545 case XPATH_OP_ROOT:
9546 xmlXPathRoot(ctxt);
9547 return (0);
9548 case XPATH_OP_NODE:
9549 if (op->ch1 != -1)
9550 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009551 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009552 if (op->ch2 != -1)
9553 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009554 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009555 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9556 return (total);
9557 case XPATH_OP_RESET:
9558 if (op->ch1 != -1)
9559 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009560 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009561 if (op->ch2 != -1)
9562 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009563 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009564 ctxt->context->node = NULL;
9565 return (total);
9566 case XPATH_OP_COLLECT:{
9567 if (op->ch1 == -1)
9568 return (total);
9569
9570 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009571 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009572
9573 /*
9574 * Optimization for [n] selection where n is a number
9575 */
9576 if ((op->ch2 != -1) &&
9577 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9578 (comp->steps[op->ch2].ch1 == -1) &&
9579 (comp->steps[op->ch2].ch2 != -1) &&
9580 (comp->steps[comp->steps[op->ch2].ch2].op ==
9581 XPATH_OP_VALUE)) {
9582 xmlXPathObjectPtr val;
9583
9584 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9585 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9586 int indx = (int) val->floatval;
9587
9588 if (val->floatval == (float) indx) {
9589 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9590 first, NULL);
9591 return (total);
9592 }
9593 }
9594 }
9595 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9596 return (total);
9597 }
9598 case XPATH_OP_VALUE:
9599 valuePush(ctxt,
9600 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9601 return (0);
9602 case XPATH_OP_SORT:
9603 if (op->ch1 != -1)
9604 total +=
9605 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9606 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009607 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009608 if ((ctxt->value != NULL)
9609 && (ctxt->value->type == XPATH_NODESET)
9610 && (ctxt->value->nodesetval != NULL))
9611 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9612 return (total);
9613 default:
9614 return (xmlXPathCompOpEval(ctxt, op));
9615 }
9616}
9617
9618/**
9619 * xmlXPathCompOpEvalLast:
9620 * @ctxt: the XPath parser context with the compiled expression
9621 * @op: an XPath compiled operation
9622 * @last: the last elem found so far
9623 *
9624 * Evaluate the Precompiled XPath operation searching only the last
9625 * element in document order
9626 *
9627 * Returns the number of node traversed
9628 */
9629static int
9630xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9631 xmlNodePtr * last)
9632{
9633 int total = 0, cur;
9634 xmlXPathCompExprPtr comp;
9635 xmlXPathObjectPtr arg1, arg2;
9636
Daniel Veillard556c6682001-10-06 09:59:51 +00009637 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009638 comp = ctxt->comp;
9639 switch (op->op) {
9640 case XPATH_OP_END:
9641 return (0);
9642 case XPATH_OP_UNION:
9643 total =
9644 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009645 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009646 if ((ctxt->value != NULL)
9647 && (ctxt->value->type == XPATH_NODESET)
9648 && (ctxt->value->nodesetval != NULL)
9649 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9650 /*
9651 * limit tree traversing to first node in the result
9652 */
9653 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9654 *last =
9655 ctxt->value->nodesetval->nodeTab[ctxt->value->
9656 nodesetval->nodeNr -
9657 1];
9658 }
9659 cur =
9660 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009661 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009662 if ((ctxt->value != NULL)
9663 && (ctxt->value->type == XPATH_NODESET)
9664 && (ctxt->value->nodesetval != NULL)
9665 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9666 }
9667 CHECK_TYPE0(XPATH_NODESET);
9668 arg2 = valuePop(ctxt);
9669
9670 CHECK_TYPE0(XPATH_NODESET);
9671 arg1 = valuePop(ctxt);
9672
9673 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9674 arg2->nodesetval);
9675 valuePush(ctxt, arg1);
9676 xmlXPathFreeObject(arg2);
9677 /* optimizer */
9678 if (total > cur)
9679 xmlXPathCompSwap(op);
9680 return (total + cur);
9681 case XPATH_OP_ROOT:
9682 xmlXPathRoot(ctxt);
9683 return (0);
9684 case XPATH_OP_NODE:
9685 if (op->ch1 != -1)
9686 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009687 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009688 if (op->ch2 != -1)
9689 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009690 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009691 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9692 return (total);
9693 case XPATH_OP_RESET:
9694 if (op->ch1 != -1)
9695 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009696 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009697 if (op->ch2 != -1)
9698 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009699 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009700 ctxt->context->node = NULL;
9701 return (total);
9702 case XPATH_OP_COLLECT:{
9703 if (op->ch1 == -1)
9704 return (0);
9705
9706 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009707 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009708
9709 /*
9710 * Optimization for [n] selection where n is a number
9711 */
9712 if ((op->ch2 != -1) &&
9713 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9714 (comp->steps[op->ch2].ch1 == -1) &&
9715 (comp->steps[op->ch2].ch2 != -1) &&
9716 (comp->steps[comp->steps[op->ch2].ch2].op ==
9717 XPATH_OP_VALUE)) {
9718 xmlXPathObjectPtr val;
9719
9720 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9721 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9722 int indx = (int) val->floatval;
9723
9724 if (val->floatval == (float) indx) {
9725 total +=
9726 xmlXPathNodeCollectAndTestNth(ctxt, op,
9727 indx, NULL,
9728 last);
9729 return (total);
9730 }
9731 }
9732 }
9733 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9734 return (total);
9735 }
9736 case XPATH_OP_VALUE:
9737 valuePush(ctxt,
9738 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9739 return (0);
9740 case XPATH_OP_SORT:
9741 if (op->ch1 != -1)
9742 total +=
9743 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9744 last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009745 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009746 if ((ctxt->value != NULL)
9747 && (ctxt->value->type == XPATH_NODESET)
9748 && (ctxt->value->nodesetval != NULL))
9749 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9750 return (total);
9751 default:
9752 return (xmlXPathCompOpEval(ctxt, op));
9753 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009754}
9755
Owen Taylor3473f882001-02-23 17:55:21 +00009756/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009757 * xmlXPathCompOpEval:
9758 * @ctxt: the XPath parser context with the compiled expression
9759 * @op: an XPath compiled operation
9760 *
9761 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009762 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009763 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009764static int
9765xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9766{
9767 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009768 int equal, ret;
9769 xmlXPathCompExprPtr comp;
9770 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009771 xmlNodePtr bak;
9772 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +00009773 int pp;
William M. Brack692092b2002-06-28 15:01:24 +00009774 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009775
Daniel Veillard556c6682001-10-06 09:59:51 +00009776 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009777 comp = ctxt->comp;
9778 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009779 case XPATH_OP_END:
9780 return (0);
9781 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009782 bakd = ctxt->context->doc;
9783 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009784 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009785 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009786 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009787 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009788 xmlXPathBooleanFunction(ctxt, 1);
9789 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9790 return (total);
9791 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009792 ctxt->context->doc = bakd;
9793 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009794 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009795 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009796 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009797 if (ctxt->error) {
9798 xmlXPathFreeObject(arg2);
9799 return(0);
9800 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009801 xmlXPathBooleanFunction(ctxt, 1);
9802 arg1 = valuePop(ctxt);
9803 arg1->boolval &= arg2->boolval;
9804 valuePush(ctxt, arg1);
9805 xmlXPathFreeObject(arg2);
9806 return (total);
9807 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009808 bakd = ctxt->context->doc;
9809 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009810 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009811 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009812 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009813 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009814 xmlXPathBooleanFunction(ctxt, 1);
9815 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9816 return (total);
9817 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009818 ctxt->context->doc = bakd;
9819 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009820 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009821 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009822 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009823 if (ctxt->error) {
9824 xmlXPathFreeObject(arg2);
9825 return(0);
9826 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009827 xmlXPathBooleanFunction(ctxt, 1);
9828 arg1 = valuePop(ctxt);
9829 arg1->boolval |= arg2->boolval;
9830 valuePush(ctxt, arg1);
9831 xmlXPathFreeObject(arg2);
9832 return (total);
9833 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009834 bakd = ctxt->context->doc;
9835 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009836 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009837 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009838 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009839 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009840 ctxt->context->doc = bakd;
9841 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009842 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009843 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009844 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009845 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +00009846 if (op->value)
9847 equal = xmlXPathEqualValues(ctxt);
9848 else
9849 equal = xmlXPathNotEqualValues(ctxt);
9850 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +00009851 return (total);
9852 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009853 bakd = ctxt->context->doc;
9854 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009855 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009856 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009857 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009858 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009859 ctxt->context->doc = bakd;
9860 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009861 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009862 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009863 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009864 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009865 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
9866 valuePush(ctxt, xmlXPathNewBoolean(ret));
9867 return (total);
9868 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009869 bakd = ctxt->context->doc;
9870 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009871 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009872 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009873 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009874 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009875 if (op->ch2 != -1) {
9876 ctxt->context->doc = bakd;
9877 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009878 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009879 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009880 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009881 }
Daniel Veillard556c6682001-10-06 09:59:51 +00009882 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009883 if (op->value == 0)
9884 xmlXPathSubValues(ctxt);
9885 else if (op->value == 1)
9886 xmlXPathAddValues(ctxt);
9887 else if (op->value == 2)
9888 xmlXPathValueFlipSign(ctxt);
9889 else if (op->value == 3) {
9890 CAST_TO_NUMBER;
9891 CHECK_TYPE0(XPATH_NUMBER);
9892 }
9893 return (total);
9894 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009895 bakd = ctxt->context->doc;
9896 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009897 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009898 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009899 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009900 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009901 ctxt->context->doc = bakd;
9902 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009903 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009904 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009905 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009906 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009907 if (op->value == 0)
9908 xmlXPathMultValues(ctxt);
9909 else if (op->value == 1)
9910 xmlXPathDivValues(ctxt);
9911 else if (op->value == 2)
9912 xmlXPathModValues(ctxt);
9913 return (total);
9914 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009915 bakd = ctxt->context->doc;
9916 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009917 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009918 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009919 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009920 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009921 ctxt->context->doc = bakd;
9922 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009923 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009924 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009925 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009926 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009927 CHECK_TYPE0(XPATH_NODESET);
9928 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009929
Daniel Veillardf06307e2001-07-03 10:35:50 +00009930 CHECK_TYPE0(XPATH_NODESET);
9931 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009932
Daniel Veillardf06307e2001-07-03 10:35:50 +00009933 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9934 arg2->nodesetval);
9935 valuePush(ctxt, arg1);
9936 xmlXPathFreeObject(arg2);
9937 return (total);
9938 case XPATH_OP_ROOT:
9939 xmlXPathRoot(ctxt);
9940 return (total);
9941 case XPATH_OP_NODE:
9942 if (op->ch1 != -1)
9943 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009944 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009945 if (op->ch2 != -1)
9946 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009947 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009948 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9949 return (total);
9950 case XPATH_OP_RESET:
9951 if (op->ch1 != -1)
9952 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009953 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009954 if (op->ch2 != -1)
9955 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009956 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009957 ctxt->context->node = NULL;
9958 return (total);
9959 case XPATH_OP_COLLECT:{
9960 if (op->ch1 == -1)
9961 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009962
Daniel Veillardf06307e2001-07-03 10:35:50 +00009963 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009964 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009965
Daniel Veillardf06307e2001-07-03 10:35:50 +00009966 /*
9967 * Optimization for [n] selection where n is a number
9968 */
9969 if ((op->ch2 != -1) &&
9970 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9971 (comp->steps[op->ch2].ch1 == -1) &&
9972 (comp->steps[op->ch2].ch2 != -1) &&
9973 (comp->steps[comp->steps[op->ch2].ch2].op ==
9974 XPATH_OP_VALUE)) {
9975 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +00009976
Daniel Veillardf06307e2001-07-03 10:35:50 +00009977 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9978 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9979 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009980
Daniel Veillardf06307e2001-07-03 10:35:50 +00009981 if (val->floatval == (float) indx) {
9982 total +=
9983 xmlXPathNodeCollectAndTestNth(ctxt, op,
9984 indx, NULL,
9985 NULL);
9986 return (total);
9987 }
9988 }
9989 }
9990 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
9991 return (total);
9992 }
9993 case XPATH_OP_VALUE:
9994 valuePush(ctxt,
9995 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9996 return (total);
9997 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +00009998 xmlXPathObjectPtr val;
9999
Daniel Veillardf06307e2001-07-03 10:35:50 +000010000 if (op->ch1 != -1)
10001 total +=
10002 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010003 if (op->value5 == NULL) {
10004 val = xmlXPathVariableLookup(ctxt->context, op->value4);
10005 if (val == NULL) {
10006 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10007 return(0);
10008 }
10009 valuePush(ctxt, val);
10010 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010011 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010012
Daniel Veillardf06307e2001-07-03 10:35:50 +000010013 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10014 if (URI == NULL) {
10015 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010016 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010017 op->value4, op->value5);
10018 return (total);
10019 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010020 val = xmlXPathVariableLookupNS(ctxt->context,
10021 op->value4, URI);
10022 if (val == NULL) {
10023 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10024 return(0);
10025 }
10026 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010027 }
10028 return (total);
10029 }
10030 case XPATH_OP_FUNCTION:{
10031 xmlXPathFunction func;
10032 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000010033 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010034
10035 if (op->ch1 != -1)
10036 total +=
10037 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010038 if (ctxt->valueNr < op->value) {
10039 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010040 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010041 ctxt->error = XPATH_INVALID_OPERAND;
10042 return (total);
10043 }
10044 for (i = 0; i < op->value; i++)
10045 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10046 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010047 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010048 ctxt->error = XPATH_INVALID_OPERAND;
10049 return (total);
10050 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010051 if (op->cache != NULL)
10052 func = (xmlXPathFunction) op->cache;
10053 else {
10054 const xmlChar *URI = NULL;
10055
10056 if (op->value5 == NULL)
10057 func =
10058 xmlXPathFunctionLookup(ctxt->context,
10059 op->value4);
10060 else {
10061 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10062 if (URI == NULL) {
10063 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010064 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010065 op->value4, op->value5);
10066 return (total);
10067 }
10068 func = xmlXPathFunctionLookupNS(ctxt->context,
10069 op->value4, URI);
10070 }
10071 if (func == NULL) {
10072 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010073 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010074 op->value4);
10075 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010076 }
10077 op->cache = (void *) func;
10078 op->cacheURI = (void *) URI;
10079 }
10080 oldFunc = ctxt->context->function;
10081 oldFuncURI = ctxt->context->functionURI;
10082 ctxt->context->function = op->value4;
10083 ctxt->context->functionURI = op->cacheURI;
10084 func(ctxt, op->value);
10085 ctxt->context->function = oldFunc;
10086 ctxt->context->functionURI = oldFuncURI;
10087 return (total);
10088 }
10089 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000010090 bakd = ctxt->context->doc;
10091 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010092 if (op->ch1 != -1)
10093 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010094 ctxt->context->doc = bakd;
10095 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010096 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010097 if (op->ch2 != -1)
10098 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010099 ctxt->context->doc = bakd;
10100 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010101 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010102 return (total);
10103 case XPATH_OP_PREDICATE:
10104 case XPATH_OP_FILTER:{
10105 xmlXPathObjectPtr res;
10106 xmlXPathObjectPtr obj, tmp;
10107 xmlNodeSetPtr newset = NULL;
10108 xmlNodeSetPtr oldset;
10109 xmlNodePtr oldnode;
10110 int i;
10111
10112 /*
10113 * Optimization for ()[1] selection i.e. the first elem
10114 */
10115 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10116 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10117 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10118 xmlXPathObjectPtr val;
10119
10120 val = comp->steps[op->ch2].value4;
10121 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10122 (val->floatval == 1.0)) {
10123 xmlNodePtr first = NULL;
10124
10125 total +=
10126 xmlXPathCompOpEvalFirst(ctxt,
10127 &comp->steps[op->ch1],
10128 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010129 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010130 /*
10131 * The nodeset should be in document order,
10132 * Keep only the first value
10133 */
10134 if ((ctxt->value != NULL) &&
10135 (ctxt->value->type == XPATH_NODESET) &&
10136 (ctxt->value->nodesetval != NULL) &&
10137 (ctxt->value->nodesetval->nodeNr > 1))
10138 ctxt->value->nodesetval->nodeNr = 1;
10139 return (total);
10140 }
10141 }
10142 /*
10143 * Optimization for ()[last()] selection i.e. the last elem
10144 */
10145 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10146 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10147 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10148 int f = comp->steps[op->ch2].ch1;
10149
10150 if ((f != -1) &&
10151 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10152 (comp->steps[f].value5 == NULL) &&
10153 (comp->steps[f].value == 0) &&
10154 (comp->steps[f].value4 != NULL) &&
10155 (xmlStrEqual
10156 (comp->steps[f].value4, BAD_CAST "last"))) {
10157 xmlNodePtr last = NULL;
10158
10159 total +=
10160 xmlXPathCompOpEvalLast(ctxt,
10161 &comp->steps[op->ch1],
10162 &last);
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 last value
10167 */
10168 if ((ctxt->value != NULL) &&
10169 (ctxt->value->type == XPATH_NODESET) &&
10170 (ctxt->value->nodesetval != NULL) &&
10171 (ctxt->value->nodesetval->nodeTab != NULL) &&
10172 (ctxt->value->nodesetval->nodeNr > 1)) {
10173 ctxt->value->nodesetval->nodeTab[0] =
10174 ctxt->value->nodesetval->nodeTab[ctxt->
10175 value->
10176 nodesetval->
10177 nodeNr -
10178 1];
10179 ctxt->value->nodesetval->nodeNr = 1;
10180 }
10181 return (total);
10182 }
10183 }
10184
10185 if (op->ch1 != -1)
10186 total +=
10187 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010188 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010189 if (op->ch2 == -1)
10190 return (total);
10191 if (ctxt->value == NULL)
10192 return (total);
10193
10194 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010195
10196#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010197 /*
10198 * Hum are we filtering the result of an XPointer expression
10199 */
10200 if (ctxt->value->type == XPATH_LOCATIONSET) {
10201 xmlLocationSetPtr newlocset = NULL;
10202 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010203
Daniel Veillardf06307e2001-07-03 10:35:50 +000010204 /*
10205 * Extract the old locset, and then evaluate the result of the
10206 * expression for all the element in the locset. use it to grow
10207 * up a new locset.
10208 */
10209 CHECK_TYPE0(XPATH_LOCATIONSET);
10210 obj = valuePop(ctxt);
10211 oldlocset = obj->user;
10212 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010213
Daniel Veillardf06307e2001-07-03 10:35:50 +000010214 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10215 ctxt->context->contextSize = 0;
10216 ctxt->context->proximityPosition = 0;
10217 if (op->ch2 != -1)
10218 total +=
10219 xmlXPathCompOpEval(ctxt,
10220 &comp->steps[op->ch2]);
10221 res = valuePop(ctxt);
10222 if (res != NULL)
10223 xmlXPathFreeObject(res);
10224 valuePush(ctxt, obj);
10225 CHECK_ERROR0;
10226 return (total);
10227 }
10228 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010229
Daniel Veillardf06307e2001-07-03 10:35:50 +000010230 for (i = 0; i < oldlocset->locNr; i++) {
10231 /*
10232 * Run the evaluation with a node list made of a
10233 * single item in the nodelocset.
10234 */
10235 ctxt->context->node = oldlocset->locTab[i]->user;
10236 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10237 valuePush(ctxt, tmp);
10238 ctxt->context->contextSize = oldlocset->locNr;
10239 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010240
Daniel Veillardf06307e2001-07-03 10:35:50 +000010241 if (op->ch2 != -1)
10242 total +=
10243 xmlXPathCompOpEval(ctxt,
10244 &comp->steps[op->ch2]);
10245 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010246
Daniel Veillardf06307e2001-07-03 10:35:50 +000010247 /*
10248 * The result of the evaluation need to be tested to
10249 * decided whether the filter succeeded or not
10250 */
10251 res = valuePop(ctxt);
10252 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10253 xmlXPtrLocationSetAdd(newlocset,
10254 xmlXPathObjectCopy
10255 (oldlocset->locTab[i]));
10256 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010257
Daniel Veillardf06307e2001-07-03 10:35:50 +000010258 /*
10259 * Cleanup
10260 */
10261 if (res != NULL)
10262 xmlXPathFreeObject(res);
10263 if (ctxt->value == tmp) {
10264 res = valuePop(ctxt);
10265 xmlXPathFreeObject(res);
10266 }
10267
10268 ctxt->context->node = NULL;
10269 }
10270
10271 /*
10272 * The result is used as the new evaluation locset.
10273 */
10274 xmlXPathFreeObject(obj);
10275 ctxt->context->node = NULL;
10276 ctxt->context->contextSize = -1;
10277 ctxt->context->proximityPosition = -1;
10278 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10279 ctxt->context->node = oldnode;
10280 return (total);
10281 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010282#endif /* LIBXML_XPTR_ENABLED */
10283
Daniel Veillardf06307e2001-07-03 10:35:50 +000010284 /*
10285 * Extract the old set, and then evaluate the result of the
10286 * expression for all the element in the set. use it to grow
10287 * up a new set.
10288 */
10289 CHECK_TYPE0(XPATH_NODESET);
10290 obj = valuePop(ctxt);
10291 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010292
Daniel Veillardf06307e2001-07-03 10:35:50 +000010293 oldnode = ctxt->context->node;
10294 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010295
Daniel Veillardf06307e2001-07-03 10:35:50 +000010296 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10297 ctxt->context->contextSize = 0;
10298 ctxt->context->proximityPosition = 0;
10299 if (op->ch2 != -1)
10300 total +=
10301 xmlXPathCompOpEval(ctxt,
10302 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010303 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010304 res = valuePop(ctxt);
10305 if (res != NULL)
10306 xmlXPathFreeObject(res);
10307 valuePush(ctxt, obj);
10308 ctxt->context->node = oldnode;
10309 CHECK_ERROR0;
10310 } else {
10311 /*
10312 * Initialize the new set.
10313 */
10314 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010315
Daniel Veillardf06307e2001-07-03 10:35:50 +000010316 for (i = 0; i < oldset->nodeNr; i++) {
10317 /*
10318 * Run the evaluation with a node list made of
10319 * a single item in the nodeset.
10320 */
10321 ctxt->context->node = oldset->nodeTab[i];
10322 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10323 valuePush(ctxt, tmp);
10324 ctxt->context->contextSize = oldset->nodeNr;
10325 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010326
Daniel Veillardf06307e2001-07-03 10:35:50 +000010327 if (op->ch2 != -1)
10328 total +=
10329 xmlXPathCompOpEval(ctxt,
10330 &comp->steps[op->ch2]);
10331 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010332
Daniel Veillardf06307e2001-07-03 10:35:50 +000010333 /*
10334 * The result of the evaluation need to be tested to
10335 * decided whether the filter succeeded or not
10336 */
10337 res = valuePop(ctxt);
10338 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10339 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10340 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010341
Daniel Veillardf06307e2001-07-03 10:35:50 +000010342 /*
10343 * Cleanup
10344 */
10345 if (res != NULL)
10346 xmlXPathFreeObject(res);
10347 if (ctxt->value == tmp) {
10348 res = valuePop(ctxt);
10349 xmlXPathFreeObject(res);
10350 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010351
Daniel Veillardf06307e2001-07-03 10:35:50 +000010352 ctxt->context->node = NULL;
10353 }
10354
10355 /*
10356 * The result is used as the new evaluation set.
10357 */
10358 xmlXPathFreeObject(obj);
10359 ctxt->context->node = NULL;
10360 ctxt->context->contextSize = -1;
10361 ctxt->context->proximityPosition = -1;
10362 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10363 }
10364 ctxt->context->node = oldnode;
10365 return (total);
10366 }
10367 case XPATH_OP_SORT:
10368 if (op->ch1 != -1)
10369 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010370 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010371 if ((ctxt->value != NULL) &&
10372 (ctxt->value->type == XPATH_NODESET) &&
10373 (ctxt->value->nodesetval != NULL))
10374 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10375 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010376#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010377 case XPATH_OP_RANGETO:{
10378 xmlXPathObjectPtr range;
10379 xmlXPathObjectPtr res, obj;
10380 xmlXPathObjectPtr tmp;
10381 xmlLocationSetPtr newset = NULL;
10382 xmlNodeSetPtr oldset;
10383 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010384
Daniel Veillardf06307e2001-07-03 10:35:50 +000010385 if (op->ch1 != -1)
10386 total +=
10387 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10388 if (op->ch2 == -1)
10389 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010390
Daniel Veillardf06307e2001-07-03 10:35:50 +000010391 CHECK_TYPE0(XPATH_NODESET);
10392 obj = valuePop(ctxt);
10393 oldset = obj->nodesetval;
10394 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010395
Daniel Veillardf06307e2001-07-03 10:35:50 +000010396 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010397
Daniel Veillardf06307e2001-07-03 10:35:50 +000010398 if (oldset != NULL) {
10399 for (i = 0; i < oldset->nodeNr; i++) {
10400 /*
10401 * Run the evaluation with a node list made of a single item
10402 * in the nodeset.
10403 */
10404 ctxt->context->node = oldset->nodeTab[i];
10405 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10406 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010407
Daniel Veillardf06307e2001-07-03 10:35:50 +000010408 if (op->ch2 != -1)
10409 total +=
10410 xmlXPathCompOpEval(ctxt,
10411 &comp->steps[op->ch2]);
10412 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010413
Daniel Veillardf06307e2001-07-03 10:35:50 +000010414 /*
10415 * The result of the evaluation need to be tested to
10416 * decided whether the filter succeeded or not
10417 */
10418 res = valuePop(ctxt);
10419 range =
10420 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10421 res);
10422 if (range != NULL) {
10423 xmlXPtrLocationSetAdd(newset, range);
10424 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010425
Daniel Veillardf06307e2001-07-03 10:35:50 +000010426 /*
10427 * Cleanup
10428 */
10429 if (res != NULL)
10430 xmlXPathFreeObject(res);
10431 if (ctxt->value == tmp) {
10432 res = valuePop(ctxt);
10433 xmlXPathFreeObject(res);
10434 }
10435
10436 ctxt->context->node = NULL;
10437 }
10438 }
10439
10440 /*
10441 * The result is used as the new evaluation set.
10442 */
10443 xmlXPathFreeObject(obj);
10444 ctxt->context->node = NULL;
10445 ctxt->context->contextSize = -1;
10446 ctxt->context->proximityPosition = -1;
10447 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
10448 return (total);
10449 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010450#endif /* LIBXML_XPTR_ENABLED */
10451 }
10452 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010453 "XPath: unknown precompiled operation %d\n", op->op);
10454 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010455}
10456
10457/**
10458 * xmlXPathRunEval:
10459 * @ctxt: the XPath parser context with the compiled expression
10460 *
10461 * Evaluate the Precompiled XPath expression in the given context.
10462 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010463static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010464xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10465 xmlXPathCompExprPtr comp;
10466
10467 if ((ctxt == NULL) || (ctxt->comp == NULL))
10468 return;
10469
10470 if (ctxt->valueTab == NULL) {
10471 /* Allocate the value stack */
10472 ctxt->valueTab = (xmlXPathObjectPtr *)
10473 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10474 if (ctxt->valueTab == NULL) {
10475 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010476 }
10477 ctxt->valueNr = 0;
10478 ctxt->valueMax = 10;
10479 ctxt->value = NULL;
10480 }
10481 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000010482 if(comp->last < 0) {
10483 xmlGenericError(xmlGenericErrorContext,
10484 "xmlXPathRunEval: last is less than zero\n");
10485 return;
10486 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010487 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10488}
10489
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010490/************************************************************************
10491 * *
10492 * Public interfaces *
10493 * *
10494 ************************************************************************/
10495
10496/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010497 * xmlXPathEvalPredicate:
10498 * @ctxt: the XPath context
10499 * @res: the Predicate Expression evaluation result
10500 *
10501 * Evaluate a predicate result for the current node.
10502 * A PredicateExpr is evaluated by evaluating the Expr and converting
10503 * the result to a boolean. If the result is a number, the result will
10504 * be converted to true if the number is equal to the position of the
10505 * context node in the context node list (as returned by the position
10506 * function) and will be converted to false otherwise; if the result
10507 * is not a number, then the result will be converted as if by a call
10508 * to the boolean function.
10509 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010510 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010511 */
10512int
10513xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
10514 if (res == NULL) return(0);
10515 switch (res->type) {
10516 case XPATH_BOOLEAN:
10517 return(res->boolval);
10518 case XPATH_NUMBER:
10519 return(res->floatval == ctxt->proximityPosition);
10520 case XPATH_NODESET:
10521 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010522 if (res->nodesetval == NULL)
10523 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010524 return(res->nodesetval->nodeNr != 0);
10525 case XPATH_STRING:
10526 return((res->stringval != NULL) &&
10527 (xmlStrlen(res->stringval) != 0));
10528 default:
10529 STRANGE
10530 }
10531 return(0);
10532}
10533
10534/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010535 * xmlXPathEvaluatePredicateResult:
10536 * @ctxt: the XPath Parser context
10537 * @res: the Predicate Expression evaluation result
10538 *
10539 * Evaluate a predicate result for the current node.
10540 * A PredicateExpr is evaluated by evaluating the Expr and converting
10541 * the result to a boolean. If the result is a number, the result will
10542 * be converted to true if the number is equal to the position of the
10543 * context node in the context node list (as returned by the position
10544 * function) and will be converted to false otherwise; if the result
10545 * is not a number, then the result will be converted as if by a call
10546 * to the boolean function.
10547 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010548 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010549 */
10550int
10551xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10552 xmlXPathObjectPtr res) {
10553 if (res == NULL) return(0);
10554 switch (res->type) {
10555 case XPATH_BOOLEAN:
10556 return(res->boolval);
10557 case XPATH_NUMBER:
10558 return(res->floatval == ctxt->context->proximityPosition);
10559 case XPATH_NODESET:
10560 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000010561 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000010562 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010563 return(res->nodesetval->nodeNr != 0);
10564 case XPATH_STRING:
10565 return((res->stringval != NULL) &&
10566 (xmlStrlen(res->stringval) != 0));
10567 default:
10568 STRANGE
10569 }
10570 return(0);
10571}
10572
10573/**
10574 * xmlXPathCompile:
10575 * @str: the XPath expression
10576 *
10577 * Compile an XPath expression
10578 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010579 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010580 * the caller has to free the object.
10581 */
10582xmlXPathCompExprPtr
10583xmlXPathCompile(const xmlChar *str) {
10584 xmlXPathParserContextPtr ctxt;
10585 xmlXPathCompExprPtr comp;
10586
10587 xmlXPathInit();
10588
10589 ctxt = xmlXPathNewParserContext(str, NULL);
10590 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010591
Daniel Veillard40af6492001-04-22 08:50:55 +000010592 if (*ctxt->cur != 0) {
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010593 /*
10594 * aleksey: in some cases this line prints *second* error message
10595 * (see bug #78858) and probably this should be fixed.
10596 * However, we are not sure that all error messages are printed
10597 * out in other places. It's not critical so we leave it as-is for now
10598 */
Daniel Veillard40af6492001-04-22 08:50:55 +000010599 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10600 comp = NULL;
10601 } else {
10602 comp = ctxt->comp;
10603 ctxt->comp = NULL;
10604 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010605 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010606 if (comp != NULL) {
Daniel Veillardceb09b92002-10-04 11:46:37 +000010607 comp->expr = xmlStrdup(str);
10608#ifdef DEBUG_EVAL_COUNTS
Daniel Veillardf06307e2001-07-03 10:35:50 +000010609 comp->string = xmlStrdup(str);
10610 comp->nb = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010611#endif
Daniel Veillardceb09b92002-10-04 11:46:37 +000010612 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010613 return(comp);
10614}
10615
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010616/**
10617 * xmlXPathCompiledEval:
10618 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000010619 * @ctx: the XPath context
10620 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010621 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000010622 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010623 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000010624 * the caller has to free the object.
10625 */
10626xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010627xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000010628 xmlXPathParserContextPtr ctxt;
10629 xmlXPathObjectPtr res, tmp, init = NULL;
10630 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000010631#ifndef LIBXML_THREAD_ENABLED
10632 static int reentance = 0;
10633#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010634
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010635 if ((comp == NULL) || (ctx == NULL))
10636 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010637 xmlXPathInit();
10638
10639 CHECK_CONTEXT(ctx)
10640
Daniel Veillard81463942001-10-16 12:34:39 +000010641#ifndef LIBXML_THREAD_ENABLED
10642 reentance++;
10643 if (reentance > 1)
10644 xmlXPathDisableOptimizer = 1;
10645#endif
10646
Daniel Veillardf06307e2001-07-03 10:35:50 +000010647#ifdef DEBUG_EVAL_COUNTS
10648 comp->nb++;
10649 if ((comp->string != NULL) && (comp->nb > 100)) {
10650 fprintf(stderr, "100 x %s\n", comp->string);
10651 comp->nb = 0;
10652 }
10653#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010654 ctxt = xmlXPathCompParserContext(comp, ctx);
10655 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010656
10657 if (ctxt->value == NULL) {
10658 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010659 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000010660 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000010661 } else {
10662 res = valuePop(ctxt);
10663 }
10664
Daniel Veillardf06307e2001-07-03 10:35:50 +000010665
Owen Taylor3473f882001-02-23 17:55:21 +000010666 do {
10667 tmp = valuePop(ctxt);
10668 if (tmp != NULL) {
10669 if (tmp != init)
10670 stack++;
10671 xmlXPathFreeObject(tmp);
10672 }
10673 } while (tmp != NULL);
10674 if ((stack != 0) && (res != NULL)) {
10675 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010676 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000010677 stack);
10678 }
10679 if (ctxt->error != XPATH_EXPRESSION_OK) {
10680 xmlXPathFreeObject(res);
10681 res = NULL;
10682 }
10683
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010684
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010685 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010686 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000010687#ifndef LIBXML_THREAD_ENABLED
10688 reentance--;
10689#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010690 return(res);
10691}
10692
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010693/**
10694 * xmlXPathEvalExpr:
10695 * @ctxt: the XPath Parser context
10696 *
10697 * Parse and evaluate an XPath expression in the given context,
10698 * then push the result on the context stack
10699 */
10700void
10701xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
10702 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010703 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010704 xmlXPathRunEval(ctxt);
10705}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010706
10707/**
10708 * xmlXPathEval:
10709 * @str: the XPath expression
10710 * @ctx: the XPath context
10711 *
10712 * Evaluate the XPath Location Path in the given context.
10713 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010714 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010715 * the caller has to free the object.
10716 */
10717xmlXPathObjectPtr
10718xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
10719 xmlXPathParserContextPtr ctxt;
10720 xmlXPathObjectPtr res, tmp, init = NULL;
10721 int stack = 0;
10722
10723 xmlXPathInit();
10724
10725 CHECK_CONTEXT(ctx)
10726
10727 ctxt = xmlXPathNewParserContext(str, ctx);
10728 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010729
10730 if (ctxt->value == NULL) {
10731 xmlGenericError(xmlGenericErrorContext,
10732 "xmlXPathEval: evaluation failed\n");
10733 res = NULL;
10734 } else if (*ctxt->cur != 0) {
10735 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10736 res = NULL;
10737 } else {
10738 res = valuePop(ctxt);
10739 }
10740
10741 do {
10742 tmp = valuePop(ctxt);
10743 if (tmp != NULL) {
10744 if (tmp != init)
10745 stack++;
10746 xmlXPathFreeObject(tmp);
10747 }
10748 } while (tmp != NULL);
10749 if ((stack != 0) && (res != NULL)) {
10750 xmlGenericError(xmlGenericErrorContext,
10751 "xmlXPathEval: %d object left on the stack\n",
10752 stack);
10753 }
10754 if (ctxt->error != XPATH_EXPRESSION_OK) {
10755 xmlXPathFreeObject(res);
10756 res = NULL;
10757 }
10758
Owen Taylor3473f882001-02-23 17:55:21 +000010759 xmlXPathFreeParserContext(ctxt);
10760 return(res);
10761}
10762
10763/**
10764 * xmlXPathEvalExpression:
10765 * @str: the XPath expression
10766 * @ctxt: the XPath context
10767 *
10768 * Evaluate the XPath expression in the given context.
10769 *
10770 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
10771 * the caller has to free the object.
10772 */
10773xmlXPathObjectPtr
10774xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
10775 xmlXPathParserContextPtr pctxt;
10776 xmlXPathObjectPtr res, tmp;
10777 int stack = 0;
10778
10779 xmlXPathInit();
10780
10781 CHECK_CONTEXT(ctxt)
10782
10783 pctxt = xmlXPathNewParserContext(str, ctxt);
10784 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010785
10786 if (*pctxt->cur != 0) {
10787 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10788 res = NULL;
10789 } else {
10790 res = valuePop(pctxt);
10791 }
10792 do {
10793 tmp = valuePop(pctxt);
10794 if (tmp != NULL) {
10795 xmlXPathFreeObject(tmp);
10796 stack++;
10797 }
10798 } while (tmp != NULL);
10799 if ((stack != 0) && (res != NULL)) {
10800 xmlGenericError(xmlGenericErrorContext,
10801 "xmlXPathEvalExpression: %d object left on the stack\n",
10802 stack);
10803 }
10804 xmlXPathFreeParserContext(pctxt);
10805 return(res);
10806}
10807
Daniel Veillard42766c02002-08-22 20:52:17 +000010808/************************************************************************
10809 * *
10810 * Extra functions not pertaining to the XPath spec *
10811 * *
10812 ************************************************************************/
10813/**
10814 * xmlXPathEscapeUriFunction:
10815 * @ctxt: the XPath Parser context
10816 * @nargs: the number of arguments
10817 *
10818 * Implement the escape-uri() XPath function
10819 * string escape-uri(string $str, bool $escape-reserved)
10820 *
10821 * This function applies the URI escaping rules defined in section 2 of [RFC
10822 * 2396] to the string supplied as $uri-part, which typically represents all
10823 * or part of a URI. The effect of the function is to replace any special
10824 * character in the string by an escape sequence of the form %xx%yy...,
10825 * where xxyy... is the hexadecimal representation of the octets used to
10826 * represent the character in UTF-8.
10827 *
10828 * The set of characters that are escaped depends on the setting of the
10829 * boolean argument $escape-reserved.
10830 *
10831 * If $escape-reserved is true, all characters are escaped other than lower
10832 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
10833 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
10834 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
10835 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
10836 * A-F).
10837 *
10838 * If $escape-reserved is false, the behavior differs in that characters
10839 * referred to in [RFC 2396] as reserved characters are not escaped. These
10840 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
10841 *
10842 * [RFC 2396] does not define whether escaped URIs should use lower case or
10843 * upper case for hexadecimal digits. To ensure that escaped URIs can be
10844 * compared using string comparison functions, this function must always use
10845 * the upper-case letters A-F.
10846 *
10847 * Generally, $escape-reserved should be set to true when escaping a string
10848 * that is to form a single part of a URI, and to false when escaping an
10849 * entire URI or URI reference.
10850 *
10851 * In the case of non-ascii characters, the string is encoded according to
10852 * utf-8 and then converted according to RFC 2396.
10853 *
10854 * Examples
10855 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
10856 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
10857 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
10858 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
10859 *
10860 */
Daniel Veillard118aed72002-09-24 14:13:13 +000010861static void
Daniel Veillard42766c02002-08-22 20:52:17 +000010862xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
10863 xmlXPathObjectPtr str;
10864 int escape_reserved;
10865 xmlBufferPtr target;
10866 xmlChar *cptr;
10867 xmlChar escape[4];
10868
10869 CHECK_ARITY(2);
10870
10871 escape_reserved = xmlXPathPopBoolean(ctxt);
10872
10873 CAST_TO_STRING;
10874 str = valuePop(ctxt);
10875
10876 target = xmlBufferCreate();
10877
10878 escape[0] = '%';
10879 escape[3] = 0;
10880
10881 if (target) {
10882 for (cptr = str->stringval; *cptr; cptr++) {
10883 if ((*cptr >= 'A' && *cptr <= 'Z') ||
10884 (*cptr >= 'a' && *cptr <= 'z') ||
10885 (*cptr >= '0' && *cptr <= '9') ||
10886 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
10887 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
10888 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
10889 (*cptr == '%' &&
10890 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
10891 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
10892 (cptr[1] >= '0' && cptr[1] <= '9')) &&
10893 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
10894 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
10895 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
10896 (!escape_reserved &&
10897 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
10898 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
10899 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
10900 *cptr == ','))) {
10901 xmlBufferAdd(target, cptr, 1);
10902 } else {
10903 if ((*cptr >> 4) < 10)
10904 escape[1] = '0' + (*cptr >> 4);
10905 else
10906 escape[1] = 'A' - 10 + (*cptr >> 4);
10907 if ((*cptr & 0xF) < 10)
10908 escape[2] = '0' + (*cptr & 0xF);
10909 else
10910 escape[2] = 'A' - 10 + (*cptr & 0xF);
10911
10912 xmlBufferAdd(target, &escape[0], 3);
10913 }
10914 }
10915 }
10916 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
10917 xmlBufferFree(target);
10918 xmlXPathFreeObject(str);
10919}
10920
Owen Taylor3473f882001-02-23 17:55:21 +000010921/**
10922 * xmlXPathRegisterAllFunctions:
10923 * @ctxt: the XPath context
10924 *
10925 * Registers all default XPath functions in this context
10926 */
10927void
10928xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
10929{
10930 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
10931 xmlXPathBooleanFunction);
10932 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
10933 xmlXPathCeilingFunction);
10934 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
10935 xmlXPathCountFunction);
10936 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
10937 xmlXPathConcatFunction);
10938 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
10939 xmlXPathContainsFunction);
10940 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
10941 xmlXPathIdFunction);
10942 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
10943 xmlXPathFalseFunction);
10944 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
10945 xmlXPathFloorFunction);
10946 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
10947 xmlXPathLastFunction);
10948 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
10949 xmlXPathLangFunction);
10950 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
10951 xmlXPathLocalNameFunction);
10952 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
10953 xmlXPathNotFunction);
10954 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
10955 xmlXPathNameFunction);
10956 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
10957 xmlXPathNamespaceURIFunction);
10958 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
10959 xmlXPathNormalizeFunction);
10960 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
10961 xmlXPathNumberFunction);
10962 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
10963 xmlXPathPositionFunction);
10964 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
10965 xmlXPathRoundFunction);
10966 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
10967 xmlXPathStringFunction);
10968 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
10969 xmlXPathStringLengthFunction);
10970 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
10971 xmlXPathStartsWithFunction);
10972 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
10973 xmlXPathSubstringFunction);
10974 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
10975 xmlXPathSubstringBeforeFunction);
10976 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
10977 xmlXPathSubstringAfterFunction);
10978 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
10979 xmlXPathSumFunction);
10980 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
10981 xmlXPathTrueFunction);
10982 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
10983 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000010984
10985 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
10986 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
10987 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000010988}
10989
10990#endif /* LIBXML_XPATH_ENABLED */