blob: 22353bab919a46d5eda0328d11ccbde232a64959 [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);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005271 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
5272 (xmlStrEqual(ctxt->context->node->parent->name,
5273 BAD_CAST "fake node libxslt")))
5274 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005275 return(ctxt->context->node->parent);
5276 case XML_ATTRIBUTE_NODE: {
5277 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5278
5279 return(att->parent);
5280 }
5281 case XML_DOCUMENT_NODE:
5282 case XML_DOCUMENT_TYPE_NODE:
5283 case XML_DOCUMENT_FRAG_NODE:
5284 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005285#ifdef LIBXML_DOCB_ENABLED
5286 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005287#endif
5288 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005289 case XML_NAMESPACE_DECL: {
5290 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5291
5292 if ((ns->next != NULL) &&
5293 (ns->next->type != XML_NAMESPACE_DECL))
5294 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005295 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005296 }
Owen Taylor3473f882001-02-23 17:55:21 +00005297 }
5298 }
5299 return(NULL);
5300}
5301
5302/**
5303 * xmlXPathNextAncestor:
5304 * @ctxt: the XPath Parser context
5305 * @cur: the current node in the traversal
5306 *
5307 * Traversal function for the "ancestor" direction
5308 * the ancestor axis contains the ancestors of the context node; the ancestors
5309 * of the context node consist of the parent of context node and the parent's
5310 * parent and so on; the nodes are ordered in reverse document order; thus the
5311 * parent is the first node on the axis, and the parent's parent is the second
5312 * node on the axis
5313 *
5314 * Returns the next element following that axis
5315 */
5316xmlNodePtr
5317xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5318 /*
5319 * the parent of an attribute or namespace node is the element
5320 * to which the attribute or namespace node is attached
5321 * !!!!!!!!!!!!!
5322 */
5323 if (cur == NULL) {
5324 if (ctxt->context->node == NULL) return(NULL);
5325 switch (ctxt->context->node->type) {
5326 case XML_ELEMENT_NODE:
5327 case XML_TEXT_NODE:
5328 case XML_CDATA_SECTION_NODE:
5329 case XML_ENTITY_REF_NODE:
5330 case XML_ENTITY_NODE:
5331 case XML_PI_NODE:
5332 case XML_COMMENT_NODE:
5333 case XML_DTD_NODE:
5334 case XML_ELEMENT_DECL:
5335 case XML_ATTRIBUTE_DECL:
5336 case XML_ENTITY_DECL:
5337 case XML_NOTATION_NODE:
5338 case XML_XINCLUDE_START:
5339 case XML_XINCLUDE_END:
5340 if (ctxt->context->node->parent == NULL)
5341 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005342 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
5343 (xmlStrEqual(ctxt->context->node->parent->name,
5344 BAD_CAST "fake node libxslt")))
5345 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005346 return(ctxt->context->node->parent);
5347 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005348 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005349
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005350 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005351 }
5352 case XML_DOCUMENT_NODE:
5353 case XML_DOCUMENT_TYPE_NODE:
5354 case XML_DOCUMENT_FRAG_NODE:
5355 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005356#ifdef LIBXML_DOCB_ENABLED
5357 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005358#endif
5359 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005360 case XML_NAMESPACE_DECL: {
5361 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5362
5363 if ((ns->next != NULL) &&
5364 (ns->next->type != XML_NAMESPACE_DECL))
5365 return((xmlNodePtr) ns->next);
5366 /* Bad, how did that namespace ended-up there ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005367 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005368 }
Owen Taylor3473f882001-02-23 17:55:21 +00005369 }
5370 return(NULL);
5371 }
5372 if (cur == ctxt->context->doc->children)
5373 return((xmlNodePtr) ctxt->context->doc);
5374 if (cur == (xmlNodePtr) ctxt->context->doc)
5375 return(NULL);
5376 switch (cur->type) {
5377 case XML_ELEMENT_NODE:
5378 case XML_TEXT_NODE:
5379 case XML_CDATA_SECTION_NODE:
5380 case XML_ENTITY_REF_NODE:
5381 case XML_ENTITY_NODE:
5382 case XML_PI_NODE:
5383 case XML_COMMENT_NODE:
5384 case XML_NOTATION_NODE:
5385 case XML_DTD_NODE:
5386 case XML_ELEMENT_DECL:
5387 case XML_ATTRIBUTE_DECL:
5388 case XML_ENTITY_DECL:
5389 case XML_XINCLUDE_START:
5390 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005391 if (cur->parent == NULL)
5392 return(NULL);
5393 if ((cur->parent->type == XML_ELEMENT_NODE) &&
5394 (xmlStrEqual(cur->parent->name, BAD_CAST "fake node libxslt")))
5395 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005396 return(cur->parent);
5397 case XML_ATTRIBUTE_NODE: {
5398 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5399
5400 return(att->parent);
5401 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005402 case XML_NAMESPACE_DECL: {
5403 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5404
5405 if ((ns->next != NULL) &&
5406 (ns->next->type != XML_NAMESPACE_DECL))
5407 return((xmlNodePtr) ns->next);
5408 /* Bad, how did that namespace ended-up there ? */
5409 return(NULL);
5410 }
Owen Taylor3473f882001-02-23 17:55:21 +00005411 case XML_DOCUMENT_NODE:
5412 case XML_DOCUMENT_TYPE_NODE:
5413 case XML_DOCUMENT_FRAG_NODE:
5414 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005415#ifdef LIBXML_DOCB_ENABLED
5416 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005417#endif
5418 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005419 }
5420 return(NULL);
5421}
5422
5423/**
5424 * xmlXPathNextAncestorOrSelf:
5425 * @ctxt: the XPath Parser context
5426 * @cur: the current node in the traversal
5427 *
5428 * Traversal function for the "ancestor-or-self" direction
5429 * he ancestor-or-self axis contains the context node and ancestors of
5430 * the context node in reverse document order; thus the context node is
5431 * the first node on the axis, and the context node's parent the second;
5432 * parent here is defined the same as with the parent axis.
5433 *
5434 * Returns the next element following that axis
5435 */
5436xmlNodePtr
5437xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5438 if (cur == NULL)
5439 return(ctxt->context->node);
5440 return(xmlXPathNextAncestor(ctxt, cur));
5441}
5442
5443/**
5444 * xmlXPathNextFollowingSibling:
5445 * @ctxt: the XPath Parser context
5446 * @cur: the current node in the traversal
5447 *
5448 * Traversal function for the "following-sibling" direction
5449 * The following-sibling axis contains the following siblings of the context
5450 * node in document order.
5451 *
5452 * Returns the next element following that axis
5453 */
5454xmlNodePtr
5455xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5456 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5457 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5458 return(NULL);
5459 if (cur == (xmlNodePtr) ctxt->context->doc)
5460 return(NULL);
5461 if (cur == NULL)
5462 return(ctxt->context->node->next);
5463 return(cur->next);
5464}
5465
5466/**
5467 * xmlXPathNextPrecedingSibling:
5468 * @ctxt: the XPath Parser context
5469 * @cur: the current node in the traversal
5470 *
5471 * Traversal function for the "preceding-sibling" direction
5472 * The preceding-sibling axis contains the preceding siblings of the context
5473 * node in reverse document order; the first preceding sibling is first on the
5474 * axis; the sibling preceding that node is the second on the axis and so on.
5475 *
5476 * Returns the next element following that axis
5477 */
5478xmlNodePtr
5479xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5480 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5481 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5482 return(NULL);
5483 if (cur == (xmlNodePtr) ctxt->context->doc)
5484 return(NULL);
5485 if (cur == NULL)
5486 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005487 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5488 cur = cur->prev;
5489 if (cur == NULL)
5490 return(ctxt->context->node->prev);
5491 }
Owen Taylor3473f882001-02-23 17:55:21 +00005492 return(cur->prev);
5493}
5494
5495/**
5496 * xmlXPathNextFollowing:
5497 * @ctxt: the XPath Parser context
5498 * @cur: the current node in the traversal
5499 *
5500 * Traversal function for the "following" direction
5501 * The following axis contains all nodes in the same document as the context
5502 * node that are after the context node in document order, excluding any
5503 * descendants and excluding attribute nodes and namespace nodes; the nodes
5504 * are ordered in document order
5505 *
5506 * Returns the next element following that axis
5507 */
5508xmlNodePtr
5509xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5510 if (cur != NULL && cur->children != NULL)
5511 return cur->children ;
5512 if (cur == NULL) cur = ctxt->context->node;
5513 if (cur == NULL) return(NULL) ; /* ERROR */
5514 if (cur->next != NULL) return(cur->next) ;
5515 do {
5516 cur = cur->parent;
5517 if (cur == NULL) return(NULL);
5518 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5519 if (cur->next != NULL) return(cur->next);
5520 } while (cur != NULL);
5521 return(cur);
5522}
5523
5524/*
5525 * xmlXPathIsAncestor:
5526 * @ancestor: the ancestor node
5527 * @node: the current node
5528 *
5529 * Check that @ancestor is a @node's ancestor
5530 *
5531 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5532 */
5533static int
5534xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5535 if ((ancestor == NULL) || (node == NULL)) return(0);
5536 /* nodes need to be in the same document */
5537 if (ancestor->doc != node->doc) return(0);
5538 /* avoid searching if ancestor or node is the root node */
5539 if (ancestor == (xmlNodePtr) node->doc) return(1);
5540 if (node == (xmlNodePtr) ancestor->doc) return(0);
5541 while (node->parent != NULL) {
5542 if (node->parent == ancestor)
5543 return(1);
5544 node = node->parent;
5545 }
5546 return(0);
5547}
5548
5549/**
5550 * xmlXPathNextPreceding:
5551 * @ctxt: the XPath Parser context
5552 * @cur: the current node in the traversal
5553 *
5554 * Traversal function for the "preceding" direction
5555 * the preceding axis contains all nodes in the same document as the context
5556 * node that are before the context node in document order, excluding any
5557 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5558 * ordered in reverse document order
5559 *
5560 * Returns the next element following that axis
5561 */
5562xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005563xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5564{
Owen Taylor3473f882001-02-23 17:55:21 +00005565 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005566 cur = ctxt->context->node;
5567 if (cur == NULL)
5568 return (NULL);
5569 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5570 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005571 do {
5572 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005573 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5574 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005575 }
5576
5577 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005578 if (cur == NULL)
5579 return (NULL);
5580 if (cur == ctxt->context->doc->children)
5581 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005582 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005583 return (cur);
5584}
5585
5586/**
5587 * xmlXPathNextPrecedingInternal:
5588 * @ctxt: the XPath Parser context
5589 * @cur: the current node in the traversal
5590 *
5591 * Traversal function for the "preceding" direction
5592 * the preceding axis contains all nodes in the same document as the context
5593 * node that are before the context node in document order, excluding any
5594 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5595 * ordered in reverse document order
5596 * This is a faster implementation but internal only since it requires a
5597 * state kept in the parser context: ctxt->ancestor.
5598 *
5599 * Returns the next element following that axis
5600 */
5601static xmlNodePtr
5602xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5603 xmlNodePtr cur)
5604{
5605 if (cur == NULL) {
5606 cur = ctxt->context->node;
5607 if (cur == NULL)
5608 return (NULL);
5609 ctxt->ancestor = cur->parent;
5610 }
5611 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5612 cur = cur->prev;
5613 while (cur->prev == NULL) {
5614 cur = cur->parent;
5615 if (cur == NULL)
5616 return (NULL);
5617 if (cur == ctxt->context->doc->children)
5618 return (NULL);
5619 if (cur != ctxt->ancestor)
5620 return (cur);
5621 ctxt->ancestor = cur->parent;
5622 }
5623 cur = cur->prev;
5624 while (cur->last != NULL)
5625 cur = cur->last;
5626 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005627}
5628
5629/**
5630 * xmlXPathNextNamespace:
5631 * @ctxt: the XPath Parser context
5632 * @cur: the current attribute in the traversal
5633 *
5634 * Traversal function for the "namespace" direction
5635 * the namespace axis contains the namespace nodes of the context node;
5636 * the order of nodes on this axis is implementation-defined; the axis will
5637 * be empty unless the context node is an element
5638 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005639 * We keep the XML namespace node at the end of the list.
5640 *
Owen Taylor3473f882001-02-23 17:55:21 +00005641 * Returns the next element following that axis
5642 */
5643xmlNodePtr
5644xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5645 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00005646 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005647 if (ctxt->context->tmpNsList != NULL)
5648 xmlFree(ctxt->context->tmpNsList);
5649 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005650 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005651 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005652 if (ctxt->context->tmpNsList != NULL) {
5653 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
5654 ctxt->context->tmpNsNr++;
5655 }
5656 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005657 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005658 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00005659 if (ctxt->context->tmpNsNr > 0) {
5660 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
5661 } else {
5662 if (ctxt->context->tmpNsList != NULL)
5663 xmlFree(ctxt->context->tmpNsList);
5664 ctxt->context->tmpNsList = NULL;
5665 return(NULL);
5666 }
Owen Taylor3473f882001-02-23 17:55:21 +00005667}
5668
5669/**
5670 * xmlXPathNextAttribute:
5671 * @ctxt: the XPath Parser context
5672 * @cur: the current attribute in the traversal
5673 *
5674 * Traversal function for the "attribute" direction
5675 * TODO: support DTD inherited default attributes
5676 *
5677 * Returns the next element following that axis
5678 */
5679xmlNodePtr
5680xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005681 if (ctxt->context->node == NULL)
5682 return(NULL);
5683 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5684 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005685 if (cur == NULL) {
5686 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5687 return(NULL);
5688 return((xmlNodePtr)ctxt->context->node->properties);
5689 }
5690 return((xmlNodePtr)cur->next);
5691}
5692
5693/************************************************************************
5694 * *
5695 * NodeTest Functions *
5696 * *
5697 ************************************************************************/
5698
Owen Taylor3473f882001-02-23 17:55:21 +00005699#define IS_FUNCTION 200
5700
Owen Taylor3473f882001-02-23 17:55:21 +00005701
5702/************************************************************************
5703 * *
5704 * Implicit tree core function library *
5705 * *
5706 ************************************************************************/
5707
5708/**
5709 * xmlXPathRoot:
5710 * @ctxt: the XPath Parser context
5711 *
5712 * Initialize the context to the root of the document
5713 */
5714void
5715xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5716 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5717 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5718}
5719
5720/************************************************************************
5721 * *
5722 * The explicit core function library *
5723 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5724 * *
5725 ************************************************************************/
5726
5727
5728/**
5729 * xmlXPathLastFunction:
5730 * @ctxt: the XPath Parser context
5731 * @nargs: the number of arguments
5732 *
5733 * Implement the last() XPath function
5734 * number last()
5735 * The last function returns the number of nodes in the context node list.
5736 */
5737void
5738xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5739 CHECK_ARITY(0);
5740 if (ctxt->context->contextSize >= 0) {
5741 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5742#ifdef DEBUG_EXPR
5743 xmlGenericError(xmlGenericErrorContext,
5744 "last() : %d\n", ctxt->context->contextSize);
5745#endif
5746 } else {
5747 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5748 }
5749}
5750
5751/**
5752 * xmlXPathPositionFunction:
5753 * @ctxt: the XPath Parser context
5754 * @nargs: the number of arguments
5755 *
5756 * Implement the position() XPath function
5757 * number position()
5758 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005759 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00005760 * will be equal to last().
5761 */
5762void
5763xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5764 CHECK_ARITY(0);
5765 if (ctxt->context->proximityPosition >= 0) {
5766 valuePush(ctxt,
5767 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5768#ifdef DEBUG_EXPR
5769 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5770 ctxt->context->proximityPosition);
5771#endif
5772 } else {
5773 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5774 }
5775}
5776
5777/**
5778 * xmlXPathCountFunction:
5779 * @ctxt: the XPath Parser context
5780 * @nargs: the number of arguments
5781 *
5782 * Implement the count() XPath function
5783 * number count(node-set)
5784 */
5785void
5786xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5787 xmlXPathObjectPtr cur;
5788
5789 CHECK_ARITY(1);
5790 if ((ctxt->value == NULL) ||
5791 ((ctxt->value->type != XPATH_NODESET) &&
5792 (ctxt->value->type != XPATH_XSLT_TREE)))
5793 XP_ERROR(XPATH_INVALID_TYPE);
5794 cur = valuePop(ctxt);
5795
Daniel Veillard911f49a2001-04-07 15:39:35 +00005796 if ((cur == NULL) || (cur->nodesetval == NULL))
5797 valuePush(ctxt, xmlXPathNewFloat((double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00005798 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00005799 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00005800 } else {
5801 if ((cur->nodesetval->nodeNr != 1) ||
5802 (cur->nodesetval->nodeTab == NULL)) {
5803 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5804 } else {
5805 xmlNodePtr tmp;
5806 int i = 0;
5807
5808 tmp = cur->nodesetval->nodeTab[0];
5809 if (tmp != NULL) {
5810 tmp = tmp->children;
5811 while (tmp != NULL) {
5812 tmp = tmp->next;
5813 i++;
5814 }
5815 }
5816 valuePush(ctxt, xmlXPathNewFloat((double) i));
5817 }
5818 }
Owen Taylor3473f882001-02-23 17:55:21 +00005819 xmlXPathFreeObject(cur);
5820}
5821
5822/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005823 * xmlXPathGetElementsByIds:
5824 * @doc: the document
5825 * @ids: a whitespace separated list of IDs
5826 *
5827 * Selects elements by their unique ID.
5828 *
5829 * Returns a node-set of selected elements.
5830 */
5831static xmlNodeSetPtr
5832xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5833 xmlNodeSetPtr ret;
5834 const xmlChar *cur = ids;
5835 xmlChar *ID;
5836 xmlAttrPtr attr;
5837 xmlNodePtr elem = NULL;
5838
5839 ret = xmlXPathNodeSetCreate(NULL);
5840
5841 while (IS_BLANK(*cur)) cur++;
5842 while (*cur != 0) {
5843 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
5844 (*cur == '.') || (*cur == '-') ||
5845 (*cur == '_') || (*cur == ':') ||
5846 (IS_COMBINING(*cur)) ||
5847 (IS_EXTENDER(*cur)))
5848 cur++;
5849
5850 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
5851
5852 ID = xmlStrndup(ids, cur - ids);
5853 attr = xmlGetID(doc, ID);
5854 if (attr != NULL) {
5855 elem = attr->parent;
5856 xmlXPathNodeSetAdd(ret, elem);
5857 }
5858 if (ID != NULL)
5859 xmlFree(ID);
5860
5861 while (IS_BLANK(*cur)) cur++;
5862 ids = cur;
5863 }
5864 return(ret);
5865}
5866
5867/**
Owen Taylor3473f882001-02-23 17:55:21 +00005868 * xmlXPathIdFunction:
5869 * @ctxt: the XPath Parser context
5870 * @nargs: the number of arguments
5871 *
5872 * Implement the id() XPath function
5873 * node-set id(object)
5874 * The id function selects elements by their unique ID
5875 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
5876 * then the result is the union of the result of applying id to the
5877 * string value of each of the nodes in the argument node-set. When the
5878 * argument to id is of any other type, the argument is converted to a
5879 * string as if by a call to the string function; the string is split
5880 * into a whitespace-separated list of tokens (whitespace is any sequence
5881 * of characters matching the production S); the result is a node-set
5882 * containing the elements in the same document as the context node that
5883 * have a unique ID equal to any of the tokens in the list.
5884 */
5885void
5886xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005887 xmlChar *tokens;
5888 xmlNodeSetPtr ret;
5889 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00005890
5891 CHECK_ARITY(1);
5892 obj = valuePop(ctxt);
5893 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00005894 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005895 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00005896 int i;
5897
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005898 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005899
Daniel Veillard911f49a2001-04-07 15:39:35 +00005900 if (obj->nodesetval != NULL) {
5901 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005902 tokens =
5903 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
5904 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
5905 ret = xmlXPathNodeSetMerge(ret, ns);
5906 xmlXPathFreeNodeSet(ns);
5907 if (tokens != NULL)
5908 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00005909 }
Owen Taylor3473f882001-02-23 17:55:21 +00005910 }
5911
5912 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005913 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005914 return;
5915 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005916 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00005917
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005918 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
5919 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005920
Owen Taylor3473f882001-02-23 17:55:21 +00005921 xmlXPathFreeObject(obj);
5922 return;
5923}
5924
5925/**
5926 * xmlXPathLocalNameFunction:
5927 * @ctxt: the XPath Parser context
5928 * @nargs: the number of arguments
5929 *
5930 * Implement the local-name() XPath function
5931 * string local-name(node-set?)
5932 * The local-name function returns a string containing the local part
5933 * of the name of the node in the argument node-set that is first in
5934 * document order. If the node-set is empty or the first node has no
5935 * name, an empty string is returned. If the argument is omitted it
5936 * defaults to the context node.
5937 */
5938void
5939xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5940 xmlXPathObjectPtr cur;
5941
5942 if (nargs == 0) {
5943 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5944 nargs = 1;
5945 }
5946
5947 CHECK_ARITY(1);
5948 if ((ctxt->value == NULL) ||
5949 ((ctxt->value->type != XPATH_NODESET) &&
5950 (ctxt->value->type != XPATH_XSLT_TREE)))
5951 XP_ERROR(XPATH_INVALID_TYPE);
5952 cur = valuePop(ctxt);
5953
Daniel Veillard911f49a2001-04-07 15:39:35 +00005954 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005955 valuePush(ctxt, xmlXPathNewCString(""));
5956 } else {
5957 int i = 0; /* Should be first in document order !!!!! */
5958 switch (cur->nodesetval->nodeTab[i]->type) {
5959 case XML_ELEMENT_NODE:
5960 case XML_ATTRIBUTE_NODE:
5961 case XML_PI_NODE:
5962 valuePush(ctxt,
5963 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
5964 break;
5965 case XML_NAMESPACE_DECL:
5966 valuePush(ctxt, xmlXPathNewString(
5967 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
5968 break;
5969 default:
5970 valuePush(ctxt, xmlXPathNewCString(""));
5971 }
5972 }
5973 xmlXPathFreeObject(cur);
5974}
5975
5976/**
5977 * xmlXPathNamespaceURIFunction:
5978 * @ctxt: the XPath Parser context
5979 * @nargs: the number of arguments
5980 *
5981 * Implement the namespace-uri() XPath function
5982 * string namespace-uri(node-set?)
5983 * The namespace-uri function returns a string containing the
5984 * namespace URI of the expanded name of the node in the argument
5985 * node-set that is first in document order. If the node-set is empty,
5986 * the first node has no name, or the expanded name has no namespace
5987 * URI, an empty string is returned. If the argument is omitted it
5988 * defaults to the context node.
5989 */
5990void
5991xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5992 xmlXPathObjectPtr cur;
5993
5994 if (nargs == 0) {
5995 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5996 nargs = 1;
5997 }
5998 CHECK_ARITY(1);
5999 if ((ctxt->value == NULL) ||
6000 ((ctxt->value->type != XPATH_NODESET) &&
6001 (ctxt->value->type != XPATH_XSLT_TREE)))
6002 XP_ERROR(XPATH_INVALID_TYPE);
6003 cur = valuePop(ctxt);
6004
Daniel Veillard911f49a2001-04-07 15:39:35 +00006005 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006006 valuePush(ctxt, xmlXPathNewCString(""));
6007 } else {
6008 int i = 0; /* Should be first in document order !!!!! */
6009 switch (cur->nodesetval->nodeTab[i]->type) {
6010 case XML_ELEMENT_NODE:
6011 case XML_ATTRIBUTE_NODE:
6012 if (cur->nodesetval->nodeTab[i]->ns == NULL)
6013 valuePush(ctxt, xmlXPathNewCString(""));
6014 else
6015 valuePush(ctxt, xmlXPathNewString(
6016 cur->nodesetval->nodeTab[i]->ns->href));
6017 break;
6018 default:
6019 valuePush(ctxt, xmlXPathNewCString(""));
6020 }
6021 }
6022 xmlXPathFreeObject(cur);
6023}
6024
6025/**
6026 * xmlXPathNameFunction:
6027 * @ctxt: the XPath Parser context
6028 * @nargs: the number of arguments
6029 *
6030 * Implement the name() XPath function
6031 * string name(node-set?)
6032 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006033 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00006034 * order. The QName must represent the name with respect to the namespace
6035 * declarations in effect on the node whose name is being represented.
6036 * Typically, this will be the form in which the name occurred in the XML
6037 * source. This need not be the case if there are namespace declarations
6038 * in effect on the node that associate multiple prefixes with the same
6039 * namespace. However, an implementation may include information about
6040 * the original prefix in its representation of nodes; in this case, an
6041 * implementation can ensure that the returned string is always the same
6042 * as the QName used in the XML source. If the argument it omitted it
6043 * defaults to the context node.
6044 * Libxml keep the original prefix so the "real qualified name" used is
6045 * returned.
6046 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006047static void
Daniel Veillard04383752001-07-08 14:27:15 +00006048xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
6049{
Owen Taylor3473f882001-02-23 17:55:21 +00006050 xmlXPathObjectPtr cur;
6051
6052 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00006053 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6054 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006055 }
6056
6057 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00006058 if ((ctxt->value == NULL) ||
6059 ((ctxt->value->type != XPATH_NODESET) &&
6060 (ctxt->value->type != XPATH_XSLT_TREE)))
6061 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006062 cur = valuePop(ctxt);
6063
Daniel Veillard911f49a2001-04-07 15:39:35 +00006064 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006065 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00006066 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006067 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00006068
Daniel Veillard04383752001-07-08 14:27:15 +00006069 switch (cur->nodesetval->nodeTab[i]->type) {
6070 case XML_ELEMENT_NODE:
6071 case XML_ATTRIBUTE_NODE:
6072 if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6073 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL))
6074 valuePush(ctxt,
6075 xmlXPathNewString(cur->nodesetval->
6076 nodeTab[i]->name));
6077
6078 else {
6079 char name[2000];
6080
6081 snprintf(name, sizeof(name), "%s:%s",
6082 (char *) cur->nodesetval->nodeTab[i]->ns->
6083 prefix,
6084 (char *) cur->nodesetval->nodeTab[i]->name);
6085 name[sizeof(name) - 1] = 0;
6086 valuePush(ctxt, xmlXPathNewCString(name));
6087 }
6088 break;
6089 default:
6090 valuePush(ctxt,
6091 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6092 xmlXPathLocalNameFunction(ctxt, 1);
6093 }
Owen Taylor3473f882001-02-23 17:55:21 +00006094 }
6095 xmlXPathFreeObject(cur);
6096}
6097
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006098
6099/**
Owen Taylor3473f882001-02-23 17:55:21 +00006100 * xmlXPathStringFunction:
6101 * @ctxt: the XPath Parser context
6102 * @nargs: the number of arguments
6103 *
6104 * Implement the string() XPath function
6105 * string string(object?)
6106 * he string function converts an object to a string as follows:
6107 * - A node-set is converted to a string by returning the value of
6108 * the node in the node-set that is first in document order.
6109 * If the node-set is empty, an empty string is returned.
6110 * - A number is converted to a string as follows
6111 * + NaN is converted to the string NaN
6112 * + positive zero is converted to the string 0
6113 * + negative zero is converted to the string 0
6114 * + positive infinity is converted to the string Infinity
6115 * + negative infinity is converted to the string -Infinity
6116 * + if the number is an integer, the number is represented in
6117 * decimal form as a Number with no decimal point and no leading
6118 * zeros, preceded by a minus sign (-) if the number is negative
6119 * + otherwise, the number is represented in decimal form as a
6120 * Number including a decimal point with at least one digit
6121 * before the decimal point and at least one digit after the
6122 * decimal point, preceded by a minus sign (-) if the number
6123 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006124 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00006125 * before the decimal point; beyond the one required digit
6126 * after the decimal point there must be as many, but only as
6127 * many, more digits as are needed to uniquely distinguish the
6128 * number from all other IEEE 754 numeric values.
6129 * - The boolean false value is converted to the string false.
6130 * The boolean true value is converted to the string true.
6131 *
6132 * If the argument is omitted, it defaults to a node-set with the
6133 * context node as its only member.
6134 */
6135void
6136xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6137 xmlXPathObjectPtr cur;
6138
6139 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006140 valuePush(ctxt,
6141 xmlXPathWrapString(
6142 xmlXPathCastNodeToString(ctxt->context->node)));
6143 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006144 }
6145
6146 CHECK_ARITY(1);
6147 cur = valuePop(ctxt);
6148 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006149 cur = xmlXPathConvertString(cur);
6150 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006151}
6152
6153/**
6154 * xmlXPathStringLengthFunction:
6155 * @ctxt: the XPath Parser context
6156 * @nargs: the number of arguments
6157 *
6158 * Implement the string-length() XPath function
6159 * number string-length(string?)
6160 * The string-length returns the number of characters in the string
6161 * (see [3.6 Strings]). If the argument is omitted, it defaults to
6162 * the context node converted to a string, in other words the value
6163 * of the context node.
6164 */
6165void
6166xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6167 xmlXPathObjectPtr cur;
6168
6169 if (nargs == 0) {
6170 if (ctxt->context->node == NULL) {
6171 valuePush(ctxt, xmlXPathNewFloat(0));
6172 } else {
6173 xmlChar *content;
6174
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006175 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006176 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00006177 xmlFree(content);
6178 }
6179 return;
6180 }
6181 CHECK_ARITY(1);
6182 CAST_TO_STRING;
6183 CHECK_TYPE(XPATH_STRING);
6184 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006185 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00006186 xmlXPathFreeObject(cur);
6187}
6188
6189/**
6190 * xmlXPathConcatFunction:
6191 * @ctxt: the XPath Parser context
6192 * @nargs: the number of arguments
6193 *
6194 * Implement the concat() XPath function
6195 * string concat(string, string, string*)
6196 * The concat function returns the concatenation of its arguments.
6197 */
6198void
6199xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6200 xmlXPathObjectPtr cur, newobj;
6201 xmlChar *tmp;
6202
6203 if (nargs < 2) {
6204 CHECK_ARITY(2);
6205 }
6206
6207 CAST_TO_STRING;
6208 cur = valuePop(ctxt);
6209 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6210 xmlXPathFreeObject(cur);
6211 return;
6212 }
6213 nargs--;
6214
6215 while (nargs > 0) {
6216 CAST_TO_STRING;
6217 newobj = valuePop(ctxt);
6218 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6219 xmlXPathFreeObject(newobj);
6220 xmlXPathFreeObject(cur);
6221 XP_ERROR(XPATH_INVALID_TYPE);
6222 }
6223 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6224 newobj->stringval = cur->stringval;
6225 cur->stringval = tmp;
6226
6227 xmlXPathFreeObject(newobj);
6228 nargs--;
6229 }
6230 valuePush(ctxt, cur);
6231}
6232
6233/**
6234 * xmlXPathContainsFunction:
6235 * @ctxt: the XPath Parser context
6236 * @nargs: the number of arguments
6237 *
6238 * Implement the contains() XPath function
6239 * boolean contains(string, string)
6240 * The contains function returns true if the first argument string
6241 * contains the second argument string, and otherwise returns false.
6242 */
6243void
6244xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6245 xmlXPathObjectPtr hay, needle;
6246
6247 CHECK_ARITY(2);
6248 CAST_TO_STRING;
6249 CHECK_TYPE(XPATH_STRING);
6250 needle = valuePop(ctxt);
6251 CAST_TO_STRING;
6252 hay = valuePop(ctxt);
6253 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6254 xmlXPathFreeObject(hay);
6255 xmlXPathFreeObject(needle);
6256 XP_ERROR(XPATH_INVALID_TYPE);
6257 }
6258 if (xmlStrstr(hay->stringval, needle->stringval))
6259 valuePush(ctxt, xmlXPathNewBoolean(1));
6260 else
6261 valuePush(ctxt, xmlXPathNewBoolean(0));
6262 xmlXPathFreeObject(hay);
6263 xmlXPathFreeObject(needle);
6264}
6265
6266/**
6267 * xmlXPathStartsWithFunction:
6268 * @ctxt: the XPath Parser context
6269 * @nargs: the number of arguments
6270 *
6271 * Implement the starts-with() XPath function
6272 * boolean starts-with(string, string)
6273 * The starts-with function returns true if the first argument string
6274 * starts with the second argument string, and otherwise returns false.
6275 */
6276void
6277xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6278 xmlXPathObjectPtr hay, needle;
6279 int n;
6280
6281 CHECK_ARITY(2);
6282 CAST_TO_STRING;
6283 CHECK_TYPE(XPATH_STRING);
6284 needle = valuePop(ctxt);
6285 CAST_TO_STRING;
6286 hay = valuePop(ctxt);
6287 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6288 xmlXPathFreeObject(hay);
6289 xmlXPathFreeObject(needle);
6290 XP_ERROR(XPATH_INVALID_TYPE);
6291 }
6292 n = xmlStrlen(needle->stringval);
6293 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6294 valuePush(ctxt, xmlXPathNewBoolean(0));
6295 else
6296 valuePush(ctxt, xmlXPathNewBoolean(1));
6297 xmlXPathFreeObject(hay);
6298 xmlXPathFreeObject(needle);
6299}
6300
6301/**
6302 * xmlXPathSubstringFunction:
6303 * @ctxt: the XPath Parser context
6304 * @nargs: the number of arguments
6305 *
6306 * Implement the substring() XPath function
6307 * string substring(string, number, number?)
6308 * The substring function returns the substring of the first argument
6309 * starting at the position specified in the second argument with
6310 * length specified in the third argument. For example,
6311 * substring("12345",2,3) returns "234". If the third argument is not
6312 * specified, it returns the substring starting at the position specified
6313 * in the second argument and continuing to the end of the string. For
6314 * example, substring("12345",2) returns "2345". More precisely, each
6315 * character in the string (see [3.6 Strings]) is considered to have a
6316 * numeric position: the position of the first character is 1, the position
6317 * of the second character is 2 and so on. The returned substring contains
6318 * those characters for which the position of the character is greater than
6319 * or equal to the second argument and, if the third argument is specified,
6320 * less than the sum of the second and third arguments; the comparisons
6321 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6322 * - substring("12345", 1.5, 2.6) returns "234"
6323 * - substring("12345", 0, 3) returns "12"
6324 * - substring("12345", 0 div 0, 3) returns ""
6325 * - substring("12345", 1, 0 div 0) returns ""
6326 * - substring("12345", -42, 1 div 0) returns "12345"
6327 * - substring("12345", -1 div 0, 1 div 0) returns ""
6328 */
6329void
6330xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6331 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006332 double le=0, in;
6333 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006334 xmlChar *ret;
6335
Owen Taylor3473f882001-02-23 17:55:21 +00006336 if (nargs < 2) {
6337 CHECK_ARITY(2);
6338 }
6339 if (nargs > 3) {
6340 CHECK_ARITY(3);
6341 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006342 /*
6343 * take care of possible last (position) argument
6344 */
Owen Taylor3473f882001-02-23 17:55:21 +00006345 if (nargs == 3) {
6346 CAST_TO_NUMBER;
6347 CHECK_TYPE(XPATH_NUMBER);
6348 len = valuePop(ctxt);
6349 le = len->floatval;
6350 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006351 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006352
Owen Taylor3473f882001-02-23 17:55:21 +00006353 CAST_TO_NUMBER;
6354 CHECK_TYPE(XPATH_NUMBER);
6355 start = valuePop(ctxt);
6356 in = start->floatval;
6357 xmlXPathFreeObject(start);
6358 CAST_TO_STRING;
6359 CHECK_TYPE(XPATH_STRING);
6360 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006361 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006362
Daniel Veillard97ac1312001-05-30 19:14:17 +00006363 /*
6364 * If last pos not present, calculate last position
6365 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006366 if (nargs != 3) {
6367 le = (double)m;
6368 if (in < 1.0)
6369 in = 1.0;
6370 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006371
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006372 /* Need to check for the special cases where either
6373 * the index is NaN, the length is NaN, or both
6374 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00006375 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006376 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006377 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00006378 * To meet the requirements of the spec, the arguments
6379 * must be converted to integer format before
6380 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006381 *
Daniel Veillard9e412302002-06-10 15:59:44 +00006382 * First we go to integer form, rounding up
6383 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006384 */
6385 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00006386 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00006387
Daniel Veillard9e412302002-06-10 15:59:44 +00006388 if (xmlXPathIsInf(le) == 1) {
6389 l = m;
6390 if (i < 1)
6391 i = 1;
6392 }
6393 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
6394 l = 0;
6395 else {
6396 l = (int) le;
6397 if (((double)l)+0.5 <= le) l++;
6398 }
6399
6400 /* Now we normalize inidices */
6401 i -= 1;
6402 l += i;
6403 if (i < 0)
6404 i = 0;
6405 if (l > m)
6406 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00006407
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006408 /* number of chars to copy */
6409 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00006410
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006411 ret = xmlUTF8Strsub(str->stringval, i, l);
6412 }
6413 else {
6414 ret = NULL;
6415 }
6416
Owen Taylor3473f882001-02-23 17:55:21 +00006417 if (ret == NULL)
6418 valuePush(ctxt, xmlXPathNewCString(""));
6419 else {
6420 valuePush(ctxt, xmlXPathNewString(ret));
6421 xmlFree(ret);
6422 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006423
Owen Taylor3473f882001-02-23 17:55:21 +00006424 xmlXPathFreeObject(str);
6425}
6426
6427/**
6428 * xmlXPathSubstringBeforeFunction:
6429 * @ctxt: the XPath Parser context
6430 * @nargs: the number of arguments
6431 *
6432 * Implement the substring-before() XPath function
6433 * string substring-before(string, string)
6434 * The substring-before function returns the substring of the first
6435 * argument string that precedes the first occurrence of the second
6436 * argument string in the first argument string, or the empty string
6437 * if the first argument string does not contain the second argument
6438 * string. For example, substring-before("1999/04/01","/") returns 1999.
6439 */
6440void
6441xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6442 xmlXPathObjectPtr str;
6443 xmlXPathObjectPtr find;
6444 xmlBufferPtr target;
6445 const xmlChar *point;
6446 int offset;
6447
6448 CHECK_ARITY(2);
6449 CAST_TO_STRING;
6450 find = valuePop(ctxt);
6451 CAST_TO_STRING;
6452 str = valuePop(ctxt);
6453
6454 target = xmlBufferCreate();
6455 if (target) {
6456 point = xmlStrstr(str->stringval, find->stringval);
6457 if (point) {
6458 offset = (int)(point - str->stringval);
6459 xmlBufferAdd(target, str->stringval, offset);
6460 }
6461 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6462 xmlBufferFree(target);
6463 }
6464
6465 xmlXPathFreeObject(str);
6466 xmlXPathFreeObject(find);
6467}
6468
6469/**
6470 * xmlXPathSubstringAfterFunction:
6471 * @ctxt: the XPath Parser context
6472 * @nargs: the number of arguments
6473 *
6474 * Implement the substring-after() XPath function
6475 * string substring-after(string, string)
6476 * The substring-after function returns the substring of the first
6477 * argument string that follows the first occurrence of the second
6478 * argument string in the first argument string, or the empty stringi
6479 * if the first argument string does not contain the second argument
6480 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6481 * and substring-after("1999/04/01","19") returns 99/04/01.
6482 */
6483void
6484xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6485 xmlXPathObjectPtr str;
6486 xmlXPathObjectPtr find;
6487 xmlBufferPtr target;
6488 const xmlChar *point;
6489 int offset;
6490
6491 CHECK_ARITY(2);
6492 CAST_TO_STRING;
6493 find = valuePop(ctxt);
6494 CAST_TO_STRING;
6495 str = valuePop(ctxt);
6496
6497 target = xmlBufferCreate();
6498 if (target) {
6499 point = xmlStrstr(str->stringval, find->stringval);
6500 if (point) {
6501 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6502 xmlBufferAdd(target, &str->stringval[offset],
6503 xmlStrlen(str->stringval) - offset);
6504 }
6505 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6506 xmlBufferFree(target);
6507 }
6508
6509 xmlXPathFreeObject(str);
6510 xmlXPathFreeObject(find);
6511}
6512
6513/**
6514 * xmlXPathNormalizeFunction:
6515 * @ctxt: the XPath Parser context
6516 * @nargs: the number of arguments
6517 *
6518 * Implement the normalize-space() XPath function
6519 * string normalize-space(string?)
6520 * The normalize-space function returns the argument string with white
6521 * space normalized by stripping leading and trailing whitespace
6522 * and replacing sequences of whitespace characters by a single
6523 * space. Whitespace characters are the same allowed by the S production
6524 * in XML. If the argument is omitted, it defaults to the context
6525 * node converted to a string, in other words the value of the context node.
6526 */
6527void
6528xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6529 xmlXPathObjectPtr obj = NULL;
6530 xmlChar *source = NULL;
6531 xmlBufferPtr target;
6532 xmlChar blank;
6533
6534 if (nargs == 0) {
6535 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006536 valuePush(ctxt,
6537 xmlXPathWrapString(
6538 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006539 nargs = 1;
6540 }
6541
6542 CHECK_ARITY(1);
6543 CAST_TO_STRING;
6544 CHECK_TYPE(XPATH_STRING);
6545 obj = valuePop(ctxt);
6546 source = obj->stringval;
6547
6548 target = xmlBufferCreate();
6549 if (target && source) {
6550
6551 /* Skip leading whitespaces */
6552 while (IS_BLANK(*source))
6553 source++;
6554
6555 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6556 blank = 0;
6557 while (*source) {
6558 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006559 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006560 } else {
6561 if (blank) {
6562 xmlBufferAdd(target, &blank, 1);
6563 blank = 0;
6564 }
6565 xmlBufferAdd(target, source, 1);
6566 }
6567 source++;
6568 }
6569
6570 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6571 xmlBufferFree(target);
6572 }
6573 xmlXPathFreeObject(obj);
6574}
6575
6576/**
6577 * xmlXPathTranslateFunction:
6578 * @ctxt: the XPath Parser context
6579 * @nargs: the number of arguments
6580 *
6581 * Implement the translate() XPath function
6582 * string translate(string, string, string)
6583 * The translate function returns the first argument string with
6584 * occurrences of characters in the second argument string replaced
6585 * by the character at the corresponding position in the third argument
6586 * string. For example, translate("bar","abc","ABC") returns the string
6587 * BAr. If there is a character in the second argument string with no
6588 * character at a corresponding position in the third argument string
6589 * (because the second argument string is longer than the third argument
6590 * string), then occurrences of that character in the first argument
6591 * string are removed. For example, translate("--aaa--","abc-","ABC")
6592 * returns "AAA". If a character occurs more than once in second
6593 * argument string, then the first occurrence determines the replacement
6594 * character. If the third argument string is longer than the second
6595 * argument string, then excess characters are ignored.
6596 */
6597void
6598xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006599 xmlXPathObjectPtr str;
6600 xmlXPathObjectPtr from;
6601 xmlXPathObjectPtr to;
6602 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006603 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006604 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006605 xmlChar *point;
6606 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006607
Daniel Veillarde043ee12001-04-16 14:08:07 +00006608 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006609
Daniel Veillarde043ee12001-04-16 14:08:07 +00006610 CAST_TO_STRING;
6611 to = valuePop(ctxt);
6612 CAST_TO_STRING;
6613 from = valuePop(ctxt);
6614 CAST_TO_STRING;
6615 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006616
Daniel Veillarde043ee12001-04-16 14:08:07 +00006617 target = xmlBufferCreate();
6618 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006619 max = xmlUTF8Strlen(to->stringval);
6620 for (cptr = str->stringval; (ch=*cptr); ) {
6621 offset = xmlUTF8Strloc(from->stringval, cptr);
6622 if (offset >= 0) {
6623 if (offset < max) {
6624 point = xmlUTF8Strpos(to->stringval, offset);
6625 if (point)
6626 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6627 }
6628 } else
6629 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6630
6631 /* Step to next character in input */
6632 cptr++;
6633 if ( ch & 0x80 ) {
6634 /* if not simple ascii, verify proper format */
6635 if ( (ch & 0xc0) != 0xc0 ) {
6636 xmlGenericError(xmlGenericErrorContext,
6637 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6638 break;
6639 }
6640 /* then skip over remaining bytes for this char */
6641 while ( (ch <<= 1) & 0x80 )
6642 if ( (*cptr++ & 0xc0) != 0x80 ) {
6643 xmlGenericError(xmlGenericErrorContext,
6644 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6645 break;
6646 }
6647 if (ch & 0x80) /* must have had error encountered */
6648 break;
6649 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006650 }
Owen Taylor3473f882001-02-23 17:55:21 +00006651 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006652 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6653 xmlBufferFree(target);
6654 xmlXPathFreeObject(str);
6655 xmlXPathFreeObject(from);
6656 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006657}
6658
6659/**
6660 * xmlXPathBooleanFunction:
6661 * @ctxt: the XPath Parser context
6662 * @nargs: the number of arguments
6663 *
6664 * Implement the boolean() XPath function
6665 * boolean boolean(object)
6666 * he boolean function converts its argument to a boolean as follows:
6667 * - a number is true if and only if it is neither positive or
6668 * negative zero nor NaN
6669 * - a node-set is true if and only if it is non-empty
6670 * - a string is true if and only if its length is non-zero
6671 */
6672void
6673xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6674 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006675
6676 CHECK_ARITY(1);
6677 cur = valuePop(ctxt);
6678 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006679 cur = xmlXPathConvertBoolean(cur);
6680 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006681}
6682
6683/**
6684 * xmlXPathNotFunction:
6685 * @ctxt: the XPath Parser context
6686 * @nargs: the number of arguments
6687 *
6688 * Implement the not() XPath function
6689 * boolean not(boolean)
6690 * The not function returns true if its argument is false,
6691 * and false otherwise.
6692 */
6693void
6694xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6695 CHECK_ARITY(1);
6696 CAST_TO_BOOLEAN;
6697 CHECK_TYPE(XPATH_BOOLEAN);
6698 ctxt->value->boolval = ! ctxt->value->boolval;
6699}
6700
6701/**
6702 * xmlXPathTrueFunction:
6703 * @ctxt: the XPath Parser context
6704 * @nargs: the number of arguments
6705 *
6706 * Implement the true() XPath function
6707 * boolean true()
6708 */
6709void
6710xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6711 CHECK_ARITY(0);
6712 valuePush(ctxt, xmlXPathNewBoolean(1));
6713}
6714
6715/**
6716 * xmlXPathFalseFunction:
6717 * @ctxt: the XPath Parser context
6718 * @nargs: the number of arguments
6719 *
6720 * Implement the false() XPath function
6721 * boolean false()
6722 */
6723void
6724xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6725 CHECK_ARITY(0);
6726 valuePush(ctxt, xmlXPathNewBoolean(0));
6727}
6728
6729/**
6730 * xmlXPathLangFunction:
6731 * @ctxt: the XPath Parser context
6732 * @nargs: the number of arguments
6733 *
6734 * Implement the lang() XPath function
6735 * boolean lang(string)
6736 * The lang function returns true or false depending on whether the
6737 * language of the context node as specified by xml:lang attributes
6738 * is the same as or is a sublanguage of the language specified by
6739 * the argument string. The language of the context node is determined
6740 * by the value of the xml:lang attribute on the context node, or, if
6741 * the context node has no xml:lang attribute, by the value of the
6742 * xml:lang attribute on the nearest ancestor of the context node that
6743 * has an xml:lang attribute. If there is no such attribute, then lang
6744 * returns false. If there is such an attribute, then lang returns
6745 * true if the attribute value is equal to the argument ignoring case,
6746 * or if there is some suffix starting with - such that the attribute
6747 * value is equal to the argument ignoring that suffix of the attribute
6748 * value and ignoring case.
6749 */
6750void
6751xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6752 xmlXPathObjectPtr val;
6753 const xmlChar *theLang;
6754 const xmlChar *lang;
6755 int ret = 0;
6756 int i;
6757
6758 CHECK_ARITY(1);
6759 CAST_TO_STRING;
6760 CHECK_TYPE(XPATH_STRING);
6761 val = valuePop(ctxt);
6762 lang = val->stringval;
6763 theLang = xmlNodeGetLang(ctxt->context->node);
6764 if ((theLang != NULL) && (lang != NULL)) {
6765 for (i = 0;lang[i] != 0;i++)
6766 if (toupper(lang[i]) != toupper(theLang[i]))
6767 goto not_equal;
6768 ret = 1;
6769 }
6770not_equal:
6771 xmlXPathFreeObject(val);
6772 valuePush(ctxt, xmlXPathNewBoolean(ret));
6773}
6774
6775/**
6776 * xmlXPathNumberFunction:
6777 * @ctxt: the XPath Parser context
6778 * @nargs: the number of arguments
6779 *
6780 * Implement the number() XPath function
6781 * number number(object?)
6782 */
6783void
6784xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6785 xmlXPathObjectPtr cur;
6786 double res;
6787
6788 if (nargs == 0) {
6789 if (ctxt->context->node == NULL) {
6790 valuePush(ctxt, xmlXPathNewFloat(0.0));
6791 } else {
6792 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6793
6794 res = xmlXPathStringEvalNumber(content);
6795 valuePush(ctxt, xmlXPathNewFloat(res));
6796 xmlFree(content);
6797 }
6798 return;
6799 }
6800
6801 CHECK_ARITY(1);
6802 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006803 cur = xmlXPathConvertNumber(cur);
6804 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006805}
6806
6807/**
6808 * xmlXPathSumFunction:
6809 * @ctxt: the XPath Parser context
6810 * @nargs: the number of arguments
6811 *
6812 * Implement the sum() XPath function
6813 * number sum(node-set)
6814 * The sum function returns the sum of the values of the nodes in
6815 * the argument node-set.
6816 */
6817void
6818xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6819 xmlXPathObjectPtr cur;
6820 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006821 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00006822
6823 CHECK_ARITY(1);
6824 if ((ctxt->value == NULL) ||
6825 ((ctxt->value->type != XPATH_NODESET) &&
6826 (ctxt->value->type != XPATH_XSLT_TREE)))
6827 XP_ERROR(XPATH_INVALID_TYPE);
6828 cur = valuePop(ctxt);
6829
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006830 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006831 valuePush(ctxt, xmlXPathNewFloat(0.0));
6832 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006833 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
6834 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006835 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006836 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00006837 }
6838 xmlXPathFreeObject(cur);
6839}
6840
6841/**
6842 * xmlXPathFloorFunction:
6843 * @ctxt: the XPath Parser context
6844 * @nargs: the number of arguments
6845 *
6846 * Implement the floor() XPath function
6847 * number floor(number)
6848 * The floor function returns the largest (closest to positive infinity)
6849 * number that is not greater than the argument and that is an integer.
6850 */
6851void
6852xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006853 double f;
6854
Owen Taylor3473f882001-02-23 17:55:21 +00006855 CHECK_ARITY(1);
6856 CAST_TO_NUMBER;
6857 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006858
6859 f = (double)((int) ctxt->value->floatval);
6860 if (f != ctxt->value->floatval) {
6861 if (ctxt->value->floatval > 0)
6862 ctxt->value->floatval = f;
6863 else
6864 ctxt->value->floatval = f - 1;
6865 }
Owen Taylor3473f882001-02-23 17:55:21 +00006866}
6867
6868/**
6869 * xmlXPathCeilingFunction:
6870 * @ctxt: the XPath Parser context
6871 * @nargs: the number of arguments
6872 *
6873 * Implement the ceiling() XPath function
6874 * number ceiling(number)
6875 * The ceiling function returns the smallest (closest to negative infinity)
6876 * number that is not less than the argument and that is an integer.
6877 */
6878void
6879xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6880 double f;
6881
6882 CHECK_ARITY(1);
6883 CAST_TO_NUMBER;
6884 CHECK_TYPE(XPATH_NUMBER);
6885
6886#if 0
6887 ctxt->value->floatval = ceil(ctxt->value->floatval);
6888#else
6889 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006890 if (f != ctxt->value->floatval) {
6891 if (ctxt->value->floatval > 0)
6892 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00006893 else {
6894 if (ctxt->value->floatval < 0 && f == 0)
6895 ctxt->value->floatval = xmlXPathNZERO;
6896 else
6897 ctxt->value->floatval = f;
6898 }
6899
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006900 }
Owen Taylor3473f882001-02-23 17:55:21 +00006901#endif
6902}
6903
6904/**
6905 * xmlXPathRoundFunction:
6906 * @ctxt: the XPath Parser context
6907 * @nargs: the number of arguments
6908 *
6909 * Implement the round() XPath function
6910 * number round(number)
6911 * The round function returns the number that is closest to the
6912 * argument and that is an integer. If there are two such numbers,
6913 * then the one that is even is returned.
6914 */
6915void
6916xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6917 double f;
6918
6919 CHECK_ARITY(1);
6920 CAST_TO_NUMBER;
6921 CHECK_TYPE(XPATH_NUMBER);
6922
Daniel Veillardcda96922001-08-21 10:56:31 +00006923 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
6924 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
6925 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00006926 (ctxt->value->floatval == 0.0))
6927 return;
6928
Owen Taylor3473f882001-02-23 17:55:21 +00006929 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006930 if (ctxt->value->floatval < 0) {
6931 if (ctxt->value->floatval < f - 0.5)
6932 ctxt->value->floatval = f - 1;
6933 else
6934 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00006935 if (ctxt->value->floatval == 0)
6936 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006937 } else {
6938 if (ctxt->value->floatval < f + 0.5)
6939 ctxt->value->floatval = f;
6940 else
6941 ctxt->value->floatval = f + 1;
6942 }
Owen Taylor3473f882001-02-23 17:55:21 +00006943}
6944
6945/************************************************************************
6946 * *
6947 * The Parser *
6948 * *
6949 ************************************************************************/
6950
6951/*
6952 * a couple of forward declarations since we use a recursive call based
6953 * implementation.
6954 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006955static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006956static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006957static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006958static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00006959static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
6960 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00006961
6962/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00006963 * xmlXPathCurrentChar:
6964 * @ctxt: the XPath parser context
6965 * @cur: pointer to the beginning of the char
6966 * @len: pointer to the length of the char read
6967 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006968 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00006969 * bytes in the input buffer.
6970 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006971 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00006972 */
6973
6974static int
6975xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
6976 unsigned char c;
6977 unsigned int val;
6978 const xmlChar *cur;
6979
6980 if (ctxt == NULL)
6981 return(0);
6982 cur = ctxt->cur;
6983
6984 /*
6985 * We are supposed to handle UTF8, check it's valid
6986 * From rfc2044: encoding of the Unicode values on UTF-8:
6987 *
6988 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
6989 * 0000 0000-0000 007F 0xxxxxxx
6990 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
6991 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
6992 *
6993 * Check for the 0x110000 limit too
6994 */
6995 c = *cur;
6996 if (c & 0x80) {
6997 if ((cur[1] & 0xc0) != 0x80)
6998 goto encoding_error;
6999 if ((c & 0xe0) == 0xe0) {
7000
7001 if ((cur[2] & 0xc0) != 0x80)
7002 goto encoding_error;
7003 if ((c & 0xf0) == 0xf0) {
7004 if (((c & 0xf8) != 0xf0) ||
7005 ((cur[3] & 0xc0) != 0x80))
7006 goto encoding_error;
7007 /* 4-byte code */
7008 *len = 4;
7009 val = (cur[0] & 0x7) << 18;
7010 val |= (cur[1] & 0x3f) << 12;
7011 val |= (cur[2] & 0x3f) << 6;
7012 val |= cur[3] & 0x3f;
7013 } else {
7014 /* 3-byte code */
7015 *len = 3;
7016 val = (cur[0] & 0xf) << 12;
7017 val |= (cur[1] & 0x3f) << 6;
7018 val |= cur[2] & 0x3f;
7019 }
7020 } else {
7021 /* 2-byte code */
7022 *len = 2;
7023 val = (cur[0] & 0x1f) << 6;
7024 val |= cur[1] & 0x3f;
7025 }
7026 if (!IS_CHAR(val)) {
7027 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
7028 }
7029 return(val);
7030 } else {
7031 /* 1-byte code */
7032 *len = 1;
7033 return((int) *cur);
7034 }
7035encoding_error:
7036 /*
7037 * If we detect an UTF8 error that probably mean that the
7038 * input encoding didn't get properly advertized in the
7039 * declaration header. Report the error and switch the encoding
7040 * to ISO-Latin-1 (if you don't like this policy, just declare the
7041 * encoding !)
7042 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00007043 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00007044 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007045}
7046
7047/**
Owen Taylor3473f882001-02-23 17:55:21 +00007048 * xmlXPathParseNCName:
7049 * @ctxt: the XPath Parser context
7050 *
7051 * parse an XML namespace non qualified name.
7052 *
7053 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7054 *
7055 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7056 * CombiningChar | Extender
7057 *
7058 * Returns the namespace name or NULL
7059 */
7060
7061xmlChar *
7062xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00007063 const xmlChar *in;
7064 xmlChar *ret;
7065 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007066
Daniel Veillard2156a562001-04-28 12:24:34 +00007067 /*
7068 * Accelerator for simple ASCII names
7069 */
7070 in = ctxt->cur;
7071 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7072 ((*in >= 0x41) && (*in <= 0x5A)) ||
7073 (*in == '_')) {
7074 in++;
7075 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7076 ((*in >= 0x41) && (*in <= 0x5A)) ||
7077 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00007078 (*in == '_') || (*in == '.') ||
7079 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00007080 in++;
7081 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7082 (*in == '[') || (*in == ']') || (*in == ':') ||
7083 (*in == '@') || (*in == '*')) {
7084 count = in - ctxt->cur;
7085 if (count == 0)
7086 return(NULL);
7087 ret = xmlStrndup(ctxt->cur, count);
7088 ctxt->cur = in;
7089 return(ret);
7090 }
7091 }
7092 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00007093}
7094
Daniel Veillard2156a562001-04-28 12:24:34 +00007095
Owen Taylor3473f882001-02-23 17:55:21 +00007096/**
7097 * xmlXPathParseQName:
7098 * @ctxt: the XPath Parser context
7099 * @prefix: a xmlChar **
7100 *
7101 * parse an XML qualified name
7102 *
7103 * [NS 5] QName ::= (Prefix ':')? LocalPart
7104 *
7105 * [NS 6] Prefix ::= NCName
7106 *
7107 * [NS 7] LocalPart ::= NCName
7108 *
7109 * Returns the function returns the local part, and prefix is updated
7110 * to get the Prefix if any.
7111 */
7112
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007113static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007114xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7115 xmlChar *ret = NULL;
7116
7117 *prefix = NULL;
7118 ret = xmlXPathParseNCName(ctxt);
7119 if (CUR == ':') {
7120 *prefix = ret;
7121 NEXT;
7122 ret = xmlXPathParseNCName(ctxt);
7123 }
7124 return(ret);
7125}
7126
7127/**
7128 * xmlXPathParseName:
7129 * @ctxt: the XPath Parser context
7130 *
7131 * parse an XML name
7132 *
7133 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7134 * CombiningChar | Extender
7135 *
7136 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7137 *
7138 * Returns the namespace name or NULL
7139 */
7140
7141xmlChar *
7142xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007143 const xmlChar *in;
7144 xmlChar *ret;
7145 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007146
Daniel Veillard61d80a22001-04-27 17:13:01 +00007147 /*
7148 * Accelerator for simple ASCII names
7149 */
7150 in = ctxt->cur;
7151 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7152 ((*in >= 0x41) && (*in <= 0x5A)) ||
7153 (*in == '_') || (*in == ':')) {
7154 in++;
7155 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7156 ((*in >= 0x41) && (*in <= 0x5A)) ||
7157 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00007158 (*in == '_') || (*in == '-') ||
7159 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00007160 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007161 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007162 count = in - ctxt->cur;
7163 ret = xmlStrndup(ctxt->cur, count);
7164 ctxt->cur = in;
7165 return(ret);
7166 }
7167 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007168 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00007169}
7170
Daniel Veillard61d80a22001-04-27 17:13:01 +00007171static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00007172xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007173 xmlChar buf[XML_MAX_NAMELEN + 5];
7174 int len = 0, l;
7175 int c;
7176
7177 /*
7178 * Handler for more complex cases
7179 */
7180 c = CUR_CHAR(l);
7181 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00007182 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7183 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00007184 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00007185 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007186 return(NULL);
7187 }
7188
7189 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7190 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7191 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007192 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007193 (IS_COMBINING(c)) ||
7194 (IS_EXTENDER(c)))) {
7195 COPY_BUF(l,buf,len,c);
7196 NEXTL(l);
7197 c = CUR_CHAR(l);
7198 if (len >= XML_MAX_NAMELEN) {
7199 /*
7200 * Okay someone managed to make a huge name, so he's ready to pay
7201 * for the processing speed.
7202 */
7203 xmlChar *buffer;
7204 int max = len * 2;
7205
7206 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
7207 if (buffer == NULL) {
7208 XP_ERROR0(XPATH_MEMORY_ERROR);
7209 }
7210 memcpy(buffer, buf, len);
7211 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7212 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007213 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007214 (IS_COMBINING(c)) ||
7215 (IS_EXTENDER(c))) {
7216 if (len + 10 > max) {
7217 max *= 2;
7218 buffer = (xmlChar *) xmlRealloc(buffer,
7219 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007220 if (buffer == NULL) {
7221 XP_ERROR0(XPATH_MEMORY_ERROR);
7222 }
7223 }
7224 COPY_BUF(l,buffer,len,c);
7225 NEXTL(l);
7226 c = CUR_CHAR(l);
7227 }
7228 buffer[len] = 0;
7229 return(buffer);
7230 }
7231 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007232 if (len == 0)
7233 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007234 return(xmlStrndup(buf, len));
7235}
Daniel Veillard3cd72402002-05-13 10:33:30 +00007236
7237#define MAX_FRAC 20
7238
7239static double my_pow10[MAX_FRAC] = {
7240 1.0, 10.0, 100.0, 1000.0, 10000.0,
7241 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7242 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7243 100000000000000.0,
7244 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
7245 1000000000000000000.0, 10000000000000000000.0
7246};
7247
Owen Taylor3473f882001-02-23 17:55:21 +00007248/**
7249 * xmlXPathStringEvalNumber:
7250 * @str: A string to scan
7251 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00007252 * [30a] Float ::= Number ('e' Digits?)?
7253 *
Owen Taylor3473f882001-02-23 17:55:21 +00007254 * [30] Number ::= Digits ('.' Digits?)?
7255 * | '.' Digits
7256 * [31] Digits ::= [0-9]+
7257 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007258 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00007259 * In complement of the Number expression, this function also handles
7260 * negative values : '-' Number.
7261 *
7262 * Returns the double value.
7263 */
7264double
7265xmlXPathStringEvalNumber(const xmlChar *str) {
7266 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00007267 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007268 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007269 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007270 int exponent = 0;
7271 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007272#ifdef __GNUC__
7273 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007274 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007275#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00007276 if (cur == NULL) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00007277 while (IS_BLANK(*cur)) cur++;
7278 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7279 return(xmlXPathNAN);
7280 }
7281 if (*cur == '-') {
7282 isneg = 1;
7283 cur++;
7284 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007285
7286#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007287 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007288 * tmp/temp is a workaround against a gcc compiler bug
7289 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007290 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007291 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007292 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007293 ret = ret * 10;
7294 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00007295 ok = 1;
7296 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00007297 temp = (double) tmp;
7298 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007299 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007300#else
Daniel Veillard7b416132002-03-07 08:36:03 +00007301 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007302 while ((*cur >= '0') && (*cur <= '9')) {
7303 ret = ret * 10 + (*cur - '0');
7304 ok = 1;
7305 cur++;
7306 }
7307#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007308
Owen Taylor3473f882001-02-23 17:55:21 +00007309 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007310 int v, frac = 0;
7311 double fraction = 0;
7312
Owen Taylor3473f882001-02-23 17:55:21 +00007313 cur++;
7314 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7315 return(xmlXPathNAN);
7316 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007317 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
7318 v = (*cur - '0');
7319 fraction = fraction * 10 + v;
7320 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007321 cur++;
7322 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007323 fraction /= my_pow10[frac];
7324 ret = ret + fraction;
7325 while ((*cur >= '0') && (*cur <= '9'))
7326 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007327 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007328 if ((*cur == 'e') || (*cur == 'E')) {
7329 cur++;
7330 if (*cur == '-') {
7331 is_exponent_negative = 1;
7332 cur++;
7333 }
7334 while ((*cur >= '0') && (*cur <= '9')) {
7335 exponent = exponent * 10 + (*cur - '0');
7336 cur++;
7337 }
7338 }
Owen Taylor3473f882001-02-23 17:55:21 +00007339 while (IS_BLANK(*cur)) cur++;
7340 if (*cur != 0) return(xmlXPathNAN);
7341 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007342 if (is_exponent_negative) exponent = -exponent;
7343 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007344 return(ret);
7345}
7346
7347/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007348 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007349 * @ctxt: the XPath Parser context
7350 *
7351 * [30] Number ::= Digits ('.' Digits?)?
7352 * | '.' Digits
7353 * [31] Digits ::= [0-9]+
7354 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007355 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007356 *
7357 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007358static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007359xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7360{
Owen Taylor3473f882001-02-23 17:55:21 +00007361 double ret = 0.0;
7362 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007363 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007364 int exponent = 0;
7365 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007366#ifdef __GNUC__
7367 unsigned long tmp = 0;
7368 double temp;
7369#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007370
7371 CHECK_ERROR;
7372 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7373 XP_ERROR(XPATH_NUMBER_ERROR);
7374 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007375#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007376 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007377 * tmp/temp is a workaround against a gcc compiler bug
7378 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007379 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007380 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007381 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007382 ret = ret * 10;
7383 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007384 ok = 1;
7385 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007386 temp = (double) tmp;
7387 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007388 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007389#else
7390 ret = 0;
7391 while ((CUR >= '0') && (CUR <= '9')) {
7392 ret = ret * 10 + (CUR - '0');
7393 ok = 1;
7394 NEXT;
7395 }
7396#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007397 if (CUR == '.') {
7398 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007399 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7400 XP_ERROR(XPATH_NUMBER_ERROR);
7401 }
7402 while ((CUR >= '0') && (CUR <= '9')) {
7403 mult /= 10;
7404 ret = ret + (CUR - '0') * mult;
7405 NEXT;
7406 }
Owen Taylor3473f882001-02-23 17:55:21 +00007407 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007408 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007409 NEXT;
7410 if (CUR == '-') {
7411 is_exponent_negative = 1;
7412 NEXT;
7413 }
7414 while ((CUR >= '0') && (CUR <= '9')) {
7415 exponent = exponent * 10 + (CUR - '0');
7416 NEXT;
7417 }
7418 if (is_exponent_negative)
7419 exponent = -exponent;
7420 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007421 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007422 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007423 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007424}
7425
7426/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007427 * xmlXPathParseLiteral:
7428 * @ctxt: the XPath Parser context
7429 *
7430 * Parse a Literal
7431 *
7432 * [29] Literal ::= '"' [^"]* '"'
7433 * | "'" [^']* "'"
7434 *
7435 * Returns the value found or NULL in case of error
7436 */
7437static xmlChar *
7438xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7439 const xmlChar *q;
7440 xmlChar *ret = NULL;
7441
7442 if (CUR == '"') {
7443 NEXT;
7444 q = CUR_PTR;
7445 while ((IS_CHAR(CUR)) && (CUR != '"'))
7446 NEXT;
7447 if (!IS_CHAR(CUR)) {
7448 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7449 } else {
7450 ret = xmlStrndup(q, CUR_PTR - q);
7451 NEXT;
7452 }
7453 } else if (CUR == '\'') {
7454 NEXT;
7455 q = CUR_PTR;
7456 while ((IS_CHAR(CUR)) && (CUR != '\''))
7457 NEXT;
7458 if (!IS_CHAR(CUR)) {
7459 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7460 } else {
7461 ret = xmlStrndup(q, CUR_PTR - q);
7462 NEXT;
7463 }
7464 } else {
7465 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7466 }
7467 return(ret);
7468}
7469
7470/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007471 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007472 * @ctxt: the XPath Parser context
7473 *
7474 * Parse a Literal and push it on the stack.
7475 *
7476 * [29] Literal ::= '"' [^"]* '"'
7477 * | "'" [^']* "'"
7478 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007479 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007480 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007481static void
7482xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007483 const xmlChar *q;
7484 xmlChar *ret = NULL;
7485
7486 if (CUR == '"') {
7487 NEXT;
7488 q = CUR_PTR;
7489 while ((IS_CHAR(CUR)) && (CUR != '"'))
7490 NEXT;
7491 if (!IS_CHAR(CUR)) {
7492 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7493 } else {
7494 ret = xmlStrndup(q, CUR_PTR - q);
7495 NEXT;
7496 }
7497 } else if (CUR == '\'') {
7498 NEXT;
7499 q = CUR_PTR;
7500 while ((IS_CHAR(CUR)) && (CUR != '\''))
7501 NEXT;
7502 if (!IS_CHAR(CUR)) {
7503 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7504 } else {
7505 ret = xmlStrndup(q, CUR_PTR - q);
7506 NEXT;
7507 }
7508 } else {
7509 XP_ERROR(XPATH_START_LITERAL_ERROR);
7510 }
7511 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007512 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7513 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007514 xmlFree(ret);
7515}
7516
7517/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007518 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007519 * @ctxt: the XPath Parser context
7520 *
7521 * Parse a VariableReference, evaluate it and push it on the stack.
7522 *
7523 * The variable bindings consist of a mapping from variable names
7524 * to variable values. The value of a variable is an object, which
7525 * of any of the types that are possible for the value of an expression,
7526 * and may also be of additional types not specified here.
7527 *
7528 * Early evaluation is possible since:
7529 * The variable bindings [...] used to evaluate a subexpression are
7530 * always the same as those used to evaluate the containing expression.
7531 *
7532 * [36] VariableReference ::= '$' QName
7533 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007534static void
7535xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007536 xmlChar *name;
7537 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007538
7539 SKIP_BLANKS;
7540 if (CUR != '$') {
7541 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7542 }
7543 NEXT;
7544 name = xmlXPathParseQName(ctxt, &prefix);
7545 if (name == NULL) {
7546 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7547 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007548 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007549 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7550 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007551 SKIP_BLANKS;
7552}
7553
7554/**
7555 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +00007556 * @name: a name string
7557 *
7558 * Is the name given a NodeType one.
7559 *
7560 * [38] NodeType ::= 'comment'
7561 * | 'text'
7562 * | 'processing-instruction'
7563 * | 'node'
7564 *
7565 * Returns 1 if true 0 otherwise
7566 */
7567int
7568xmlXPathIsNodeType(const xmlChar *name) {
7569 if (name == NULL)
7570 return(0);
7571
Daniel Veillard1971ee22002-01-31 20:29:19 +00007572 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007573 return(1);
7574 if (xmlStrEqual(name, BAD_CAST "text"))
7575 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007576 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007577 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007578 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007579 return(1);
7580 return(0);
7581}
7582
7583/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007584 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007585 * @ctxt: the XPath Parser context
7586 *
7587 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7588 * [17] Argument ::= Expr
7589 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007590 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007591 * pushed on the stack
7592 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007593static void
7594xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007595 xmlChar *name;
7596 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007597 int nbargs = 0;
7598
7599 name = xmlXPathParseQName(ctxt, &prefix);
7600 if (name == NULL) {
7601 XP_ERROR(XPATH_EXPR_ERROR);
7602 }
7603 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007604#ifdef DEBUG_EXPR
7605 if (prefix == NULL)
7606 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7607 name);
7608 else
7609 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7610 prefix, name);
7611#endif
7612
Owen Taylor3473f882001-02-23 17:55:21 +00007613 if (CUR != '(') {
7614 XP_ERROR(XPATH_EXPR_ERROR);
7615 }
7616 NEXT;
7617 SKIP_BLANKS;
7618
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007619 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007620 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007621 int op1 = ctxt->comp->last;
7622 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007623 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007624 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007625 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007626 nbargs++;
7627 if (CUR == ')') break;
7628 if (CUR != ',') {
7629 XP_ERROR(XPATH_EXPR_ERROR);
7630 }
7631 NEXT;
7632 SKIP_BLANKS;
7633 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007634 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7635 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007636 NEXT;
7637 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007638}
7639
7640/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007641 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007642 * @ctxt: the XPath Parser context
7643 *
7644 * [15] PrimaryExpr ::= VariableReference
7645 * | '(' Expr ')'
7646 * | Literal
7647 * | Number
7648 * | FunctionCall
7649 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007650 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007651 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007652static void
7653xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007654 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007655 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007656 else if (CUR == '(') {
7657 NEXT;
7658 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007659 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007660 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00007661 if (CUR != ')') {
7662 XP_ERROR(XPATH_EXPR_ERROR);
7663 }
7664 NEXT;
7665 SKIP_BLANKS;
Daniel Veillard01917aa2002-04-10 11:30:41 +00007666 } else if (IS_DIGIT(CUR) || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007667 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007668 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007669 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007670 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007671 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007672 }
7673 SKIP_BLANKS;
7674}
7675
7676/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007677 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007678 * @ctxt: the XPath Parser context
7679 *
7680 * [20] FilterExpr ::= PrimaryExpr
7681 * | FilterExpr Predicate
7682 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007683 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007684 * Square brackets are used to filter expressions in the same way that
7685 * they are used in location paths. It is an error if the expression to
7686 * be filtered does not evaluate to a node-set. The context node list
7687 * used for evaluating the expression in square brackets is the node-set
7688 * to be filtered listed in document order.
7689 */
7690
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007691static void
7692xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
7693 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007694 CHECK_ERROR;
7695 SKIP_BLANKS;
7696
7697 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007698 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00007699 SKIP_BLANKS;
7700 }
7701
7702
7703}
7704
7705/**
7706 * xmlXPathScanName:
7707 * @ctxt: the XPath Parser context
7708 *
7709 * Trickery: parse an XML name but without consuming the input flow
7710 * Needed to avoid insanity in the parser state.
7711 *
7712 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7713 * CombiningChar | Extender
7714 *
7715 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7716 *
7717 * [6] Names ::= Name (S Name)*
7718 *
7719 * Returns the Name parsed or NULL
7720 */
7721
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007722static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007723xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7724 xmlChar buf[XML_MAX_NAMELEN];
7725 int len = 0;
7726
7727 SKIP_BLANKS;
7728 if (!IS_LETTER(CUR) && (CUR != '_') &&
7729 (CUR != ':')) {
7730 return(NULL);
7731 }
7732
7733 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7734 (NXT(len) == '.') || (NXT(len) == '-') ||
7735 (NXT(len) == '_') || (NXT(len) == ':') ||
7736 (IS_COMBINING(NXT(len))) ||
7737 (IS_EXTENDER(NXT(len)))) {
7738 buf[len] = NXT(len);
7739 len++;
7740 if (len >= XML_MAX_NAMELEN) {
7741 xmlGenericError(xmlGenericErrorContext,
7742 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
7743 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7744 (NXT(len) == '.') || (NXT(len) == '-') ||
7745 (NXT(len) == '_') || (NXT(len) == ':') ||
7746 (IS_COMBINING(NXT(len))) ||
7747 (IS_EXTENDER(NXT(len))))
7748 len++;
7749 break;
7750 }
7751 }
7752 return(xmlStrndup(buf, len));
7753}
7754
7755/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007756 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007757 * @ctxt: the XPath Parser context
7758 *
7759 * [19] PathExpr ::= LocationPath
7760 * | FilterExpr
7761 * | FilterExpr '/' RelativeLocationPath
7762 * | FilterExpr '//' RelativeLocationPath
7763 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007764 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007765 * The / operator and // operators combine an arbitrary expression
7766 * and a relative location path. It is an error if the expression
7767 * does not evaluate to a node-set.
7768 * The / operator does composition in the same way as when / is
7769 * used in a location path. As in location paths, // is short for
7770 * /descendant-or-self::node()/.
7771 */
7772
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007773static void
7774xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007775 int lc = 1; /* Should we branch to LocationPath ? */
7776 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7777
7778 SKIP_BLANKS;
7779 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
Daniel Veillard01917aa2002-04-10 11:30:41 +00007780 (CUR == '\'') || (CUR == '"') || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00007781 lc = 0;
7782 } else if (CUR == '*') {
7783 /* relative or absolute location path */
7784 lc = 1;
7785 } else if (CUR == '/') {
7786 /* relative or absolute location path */
7787 lc = 1;
7788 } else if (CUR == '@') {
7789 /* relative abbreviated attribute location path */
7790 lc = 1;
7791 } else if (CUR == '.') {
7792 /* relative abbreviated attribute location path */
7793 lc = 1;
7794 } else {
7795 /*
7796 * Problem is finding if we have a name here whether it's:
7797 * - a nodetype
7798 * - a function call in which case it's followed by '('
7799 * - an axis in which case it's followed by ':'
7800 * - a element name
7801 * We do an a priori analysis here rather than having to
7802 * maintain parsed token content through the recursive function
7803 * calls. This looks uglier but makes the code quite easier to
7804 * read/write/debug.
7805 */
7806 SKIP_BLANKS;
7807 name = xmlXPathScanName(ctxt);
7808 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7809#ifdef DEBUG_STEP
7810 xmlGenericError(xmlGenericErrorContext,
7811 "PathExpr: Axis\n");
7812#endif
7813 lc = 1;
7814 xmlFree(name);
7815 } else if (name != NULL) {
7816 int len =xmlStrlen(name);
7817 int blank = 0;
7818
7819
7820 while (NXT(len) != 0) {
7821 if (NXT(len) == '/') {
7822 /* element name */
7823#ifdef DEBUG_STEP
7824 xmlGenericError(xmlGenericErrorContext,
7825 "PathExpr: AbbrRelLocation\n");
7826#endif
7827 lc = 1;
7828 break;
7829 } else if (IS_BLANK(NXT(len))) {
7830 /* skip to next */
7831 blank = 1;
7832 } else if (NXT(len) == ':') {
7833#ifdef DEBUG_STEP
7834 xmlGenericError(xmlGenericErrorContext,
7835 "PathExpr: AbbrRelLocation\n");
7836#endif
7837 lc = 1;
7838 break;
7839 } else if ((NXT(len) == '(')) {
7840 /* Note Type or Function */
7841 if (xmlXPathIsNodeType(name)) {
7842#ifdef DEBUG_STEP
7843 xmlGenericError(xmlGenericErrorContext,
7844 "PathExpr: Type search\n");
7845#endif
7846 lc = 1;
7847 } else {
7848#ifdef DEBUG_STEP
7849 xmlGenericError(xmlGenericErrorContext,
7850 "PathExpr: function call\n");
7851#endif
7852 lc = 0;
7853 }
7854 break;
7855 } else if ((NXT(len) == '[')) {
7856 /* element name */
7857#ifdef DEBUG_STEP
7858 xmlGenericError(xmlGenericErrorContext,
7859 "PathExpr: AbbrRelLocation\n");
7860#endif
7861 lc = 1;
7862 break;
7863 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
7864 (NXT(len) == '=')) {
7865 lc = 1;
7866 break;
7867 } else {
7868 lc = 1;
7869 break;
7870 }
7871 len++;
7872 }
7873 if (NXT(len) == 0) {
7874#ifdef DEBUG_STEP
7875 xmlGenericError(xmlGenericErrorContext,
7876 "PathExpr: AbbrRelLocation\n");
7877#endif
7878 /* element name */
7879 lc = 1;
7880 }
7881 xmlFree(name);
7882 } else {
7883 /* make sure all cases are covered explicitely */
7884 XP_ERROR(XPATH_EXPR_ERROR);
7885 }
7886 }
7887
7888 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007889 if (CUR == '/') {
7890 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
7891 } else {
7892 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007893 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007894 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007895 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007896 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007897 CHECK_ERROR;
7898 if ((CUR == '/') && (NXT(1) == '/')) {
7899 SKIP(2);
7900 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007901
7902 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7903 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
7904 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
7905
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007906 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007907 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007908 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007909 }
7910 }
7911 SKIP_BLANKS;
7912}
7913
7914/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007915 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007916 * @ctxt: the XPath Parser context
7917 *
7918 * [18] UnionExpr ::= PathExpr
7919 * | UnionExpr '|' PathExpr
7920 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007921 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007922 */
7923
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007924static void
7925xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
7926 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007927 CHECK_ERROR;
7928 SKIP_BLANKS;
7929 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007930 int op1 = ctxt->comp->last;
7931 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007932
7933 NEXT;
7934 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007935 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007936
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007937 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
7938
Owen Taylor3473f882001-02-23 17:55:21 +00007939 SKIP_BLANKS;
7940 }
Owen Taylor3473f882001-02-23 17:55:21 +00007941}
7942
7943/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007944 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007945 * @ctxt: the XPath Parser context
7946 *
7947 * [27] UnaryExpr ::= UnionExpr
7948 * | '-' UnaryExpr
7949 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007950 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007951 */
7952
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007953static void
7954xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007955 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007956 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007957
7958 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00007959 while (CUR == '-') {
7960 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007961 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007962 NEXT;
7963 SKIP_BLANKS;
7964 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007965
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007966 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007967 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007968 if (found) {
7969 if (minus)
7970 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
7971 else
7972 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007973 }
7974}
7975
7976/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007977 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007978 * @ctxt: the XPath Parser context
7979 *
7980 * [26] MultiplicativeExpr ::= UnaryExpr
7981 * | MultiplicativeExpr MultiplyOperator UnaryExpr
7982 * | MultiplicativeExpr 'div' UnaryExpr
7983 * | MultiplicativeExpr 'mod' UnaryExpr
7984 * [34] MultiplyOperator ::= '*'
7985 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007986 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007987 */
7988
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007989static void
7990xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
7991 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007992 CHECK_ERROR;
7993 SKIP_BLANKS;
7994 while ((CUR == '*') ||
7995 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
7996 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
7997 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007998 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007999
8000 if (CUR == '*') {
8001 op = 0;
8002 NEXT;
8003 } else if (CUR == 'd') {
8004 op = 1;
8005 SKIP(3);
8006 } else if (CUR == 'm') {
8007 op = 2;
8008 SKIP(3);
8009 }
8010 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008011 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008012 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008013 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008014 SKIP_BLANKS;
8015 }
8016}
8017
8018/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008019 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008020 * @ctxt: the XPath Parser context
8021 *
8022 * [25] AdditiveExpr ::= MultiplicativeExpr
8023 * | AdditiveExpr '+' MultiplicativeExpr
8024 * | AdditiveExpr '-' MultiplicativeExpr
8025 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008026 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008027 */
8028
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008029static void
8030xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008031
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008032 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008033 CHECK_ERROR;
8034 SKIP_BLANKS;
8035 while ((CUR == '+') || (CUR == '-')) {
8036 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008037 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008038
8039 if (CUR == '+') plus = 1;
8040 else plus = 0;
8041 NEXT;
8042 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008043 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008044 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008045 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008046 SKIP_BLANKS;
8047 }
8048}
8049
8050/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008051 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008052 * @ctxt: the XPath Parser context
8053 *
8054 * [24] RelationalExpr ::= AdditiveExpr
8055 * | RelationalExpr '<' AdditiveExpr
8056 * | RelationalExpr '>' AdditiveExpr
8057 * | RelationalExpr '<=' AdditiveExpr
8058 * | RelationalExpr '>=' AdditiveExpr
8059 *
8060 * A <= B > C is allowed ? Answer from James, yes with
8061 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8062 * which is basically what got implemented.
8063 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008064 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00008065 * on the stack
8066 */
8067
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008068static void
8069xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8070 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008071 CHECK_ERROR;
8072 SKIP_BLANKS;
8073 while ((CUR == '<') ||
8074 (CUR == '>') ||
8075 ((CUR == '<') && (NXT(1) == '=')) ||
8076 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008077 int inf, strict;
8078 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008079
8080 if (CUR == '<') inf = 1;
8081 else inf = 0;
8082 if (NXT(1) == '=') strict = 0;
8083 else strict = 1;
8084 NEXT;
8085 if (!strict) NEXT;
8086 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008087 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008088 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008089 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00008090 SKIP_BLANKS;
8091 }
8092}
8093
8094/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008095 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008096 * @ctxt: the XPath Parser context
8097 *
8098 * [23] EqualityExpr ::= RelationalExpr
8099 * | EqualityExpr '=' RelationalExpr
8100 * | EqualityExpr '!=' RelationalExpr
8101 *
8102 * A != B != C is allowed ? Answer from James, yes with
8103 * (RelationalExpr = RelationalExpr) = RelationalExpr
8104 * (RelationalExpr != RelationalExpr) != RelationalExpr
8105 * which is basically what got implemented.
8106 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008107 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008108 *
8109 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008110static void
8111xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8112 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008113 CHECK_ERROR;
8114 SKIP_BLANKS;
8115 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008116 int eq;
8117 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008118
8119 if (CUR == '=') eq = 1;
8120 else eq = 0;
8121 NEXT;
8122 if (!eq) NEXT;
8123 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008124 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008125 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008126 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008127 SKIP_BLANKS;
8128 }
8129}
8130
8131/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008132 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008133 * @ctxt: the XPath Parser context
8134 *
8135 * [22] AndExpr ::= EqualityExpr
8136 * | AndExpr 'and' EqualityExpr
8137 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008138 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008139 *
8140 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008141static void
8142xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8143 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008144 CHECK_ERROR;
8145 SKIP_BLANKS;
8146 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008147 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008148 SKIP(3);
8149 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008150 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008151 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008152 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008153 SKIP_BLANKS;
8154 }
8155}
8156
8157/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008158 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008159 * @ctxt: the XPath Parser context
8160 *
8161 * [14] Expr ::= OrExpr
8162 * [21] OrExpr ::= AndExpr
8163 * | OrExpr 'or' AndExpr
8164 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008165 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00008166 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008167static void
8168xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8169 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008170 CHECK_ERROR;
8171 SKIP_BLANKS;
8172 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008173 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008174 SKIP(2);
8175 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008176 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008177 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008178 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8179 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00008180 SKIP_BLANKS;
8181 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008182 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8183 /* more ops could be optimized too */
8184 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8185 }
Owen Taylor3473f882001-02-23 17:55:21 +00008186}
8187
8188/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008189 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00008190 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008191 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00008192 *
8193 * [8] Predicate ::= '[' PredicateExpr ']'
8194 * [9] PredicateExpr ::= Expr
8195 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008196 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008197 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008198static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008199xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008200 int op1 = ctxt->comp->last;
8201
8202 SKIP_BLANKS;
8203 if (CUR != '[') {
8204 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8205 }
8206 NEXT;
8207 SKIP_BLANKS;
8208
8209 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008210 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008211 CHECK_ERROR;
8212
8213 if (CUR != ']') {
8214 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8215 }
8216
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008217 if (filter)
8218 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8219 else
8220 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008221
8222 NEXT;
8223 SKIP_BLANKS;
8224}
8225
8226/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008227 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00008228 * @ctxt: the XPath Parser context
8229 * @test: pointer to a xmlXPathTestVal
8230 * @type: pointer to a xmlXPathTypeVal
8231 * @prefix: placeholder for a possible name prefix
8232 *
8233 * [7] NodeTest ::= NameTest
8234 * | NodeType '(' ')'
8235 * | 'processing-instruction' '(' Literal ')'
8236 *
8237 * [37] NameTest ::= '*'
8238 * | NCName ':' '*'
8239 * | QName
8240 * [38] NodeType ::= 'comment'
8241 * | 'text'
8242 * | 'processing-instruction'
8243 * | 'node'
8244 *
8245 * Returns the name found and update @test, @type and @prefix appropriately
8246 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008247static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008248xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8249 xmlXPathTypeVal *type, const xmlChar **prefix,
8250 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008251 int blanks;
8252
8253 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8254 STRANGE;
8255 return(NULL);
8256 }
8257 *type = 0;
8258 *test = 0;
8259 *prefix = NULL;
8260 SKIP_BLANKS;
8261
8262 if ((name == NULL) && (CUR == '*')) {
8263 /*
8264 * All elements
8265 */
8266 NEXT;
8267 *test = NODE_TEST_ALL;
8268 return(NULL);
8269 }
8270
8271 if (name == NULL)
8272 name = xmlXPathParseNCName(ctxt);
8273 if (name == NULL) {
8274 XP_ERROR0(XPATH_EXPR_ERROR);
8275 }
8276
8277 blanks = IS_BLANK(CUR);
8278 SKIP_BLANKS;
8279 if (CUR == '(') {
8280 NEXT;
8281 /*
8282 * NodeType or PI search
8283 */
8284 if (xmlStrEqual(name, BAD_CAST "comment"))
8285 *type = NODE_TYPE_COMMENT;
8286 else if (xmlStrEqual(name, BAD_CAST "node"))
8287 *type = NODE_TYPE_NODE;
8288 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8289 *type = NODE_TYPE_PI;
8290 else if (xmlStrEqual(name, BAD_CAST "text"))
8291 *type = NODE_TYPE_TEXT;
8292 else {
8293 if (name != NULL)
8294 xmlFree(name);
8295 XP_ERROR0(XPATH_EXPR_ERROR);
8296 }
8297
8298 *test = NODE_TEST_TYPE;
8299
8300 SKIP_BLANKS;
8301 if (*type == NODE_TYPE_PI) {
8302 /*
8303 * Specific case: search a PI by name.
8304 */
Owen Taylor3473f882001-02-23 17:55:21 +00008305 if (name != NULL)
8306 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008307 name = NULL;
8308 if (CUR != ')') {
8309 name = xmlXPathParseLiteral(ctxt);
8310 CHECK_ERROR 0;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00008311 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00008312 SKIP_BLANKS;
8313 }
Owen Taylor3473f882001-02-23 17:55:21 +00008314 }
8315 if (CUR != ')') {
8316 if (name != NULL)
8317 xmlFree(name);
8318 XP_ERROR0(XPATH_UNCLOSED_ERROR);
8319 }
8320 NEXT;
8321 return(name);
8322 }
8323 *test = NODE_TEST_NAME;
8324 if ((!blanks) && (CUR == ':')) {
8325 NEXT;
8326
8327 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008328 * Since currently the parser context don't have a
8329 * namespace list associated:
8330 * The namespace name for this prefix can be computed
8331 * only at evaluation time. The compilation is done
8332 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008333 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008334#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008335 *prefix = xmlXPathNsLookup(ctxt->context, name);
8336 if (name != NULL)
8337 xmlFree(name);
8338 if (*prefix == NULL) {
8339 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8340 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008341#else
8342 *prefix = name;
8343#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008344
8345 if (CUR == '*') {
8346 /*
8347 * All elements
8348 */
8349 NEXT;
8350 *test = NODE_TEST_ALL;
8351 return(NULL);
8352 }
8353
8354 name = xmlXPathParseNCName(ctxt);
8355 if (name == NULL) {
8356 XP_ERROR0(XPATH_EXPR_ERROR);
8357 }
8358 }
8359 return(name);
8360}
8361
8362/**
8363 * xmlXPathIsAxisName:
8364 * @name: a preparsed name token
8365 *
8366 * [6] AxisName ::= 'ancestor'
8367 * | 'ancestor-or-self'
8368 * | 'attribute'
8369 * | 'child'
8370 * | 'descendant'
8371 * | 'descendant-or-self'
8372 * | 'following'
8373 * | 'following-sibling'
8374 * | 'namespace'
8375 * | 'parent'
8376 * | 'preceding'
8377 * | 'preceding-sibling'
8378 * | 'self'
8379 *
8380 * Returns the axis or 0
8381 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008382static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008383xmlXPathIsAxisName(const xmlChar *name) {
8384 xmlXPathAxisVal ret = 0;
8385 switch (name[0]) {
8386 case 'a':
8387 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8388 ret = AXIS_ANCESTOR;
8389 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8390 ret = AXIS_ANCESTOR_OR_SELF;
8391 if (xmlStrEqual(name, BAD_CAST "attribute"))
8392 ret = AXIS_ATTRIBUTE;
8393 break;
8394 case 'c':
8395 if (xmlStrEqual(name, BAD_CAST "child"))
8396 ret = AXIS_CHILD;
8397 break;
8398 case 'd':
8399 if (xmlStrEqual(name, BAD_CAST "descendant"))
8400 ret = AXIS_DESCENDANT;
8401 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8402 ret = AXIS_DESCENDANT_OR_SELF;
8403 break;
8404 case 'f':
8405 if (xmlStrEqual(name, BAD_CAST "following"))
8406 ret = AXIS_FOLLOWING;
8407 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8408 ret = AXIS_FOLLOWING_SIBLING;
8409 break;
8410 case 'n':
8411 if (xmlStrEqual(name, BAD_CAST "namespace"))
8412 ret = AXIS_NAMESPACE;
8413 break;
8414 case 'p':
8415 if (xmlStrEqual(name, BAD_CAST "parent"))
8416 ret = AXIS_PARENT;
8417 if (xmlStrEqual(name, BAD_CAST "preceding"))
8418 ret = AXIS_PRECEDING;
8419 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8420 ret = AXIS_PRECEDING_SIBLING;
8421 break;
8422 case 's':
8423 if (xmlStrEqual(name, BAD_CAST "self"))
8424 ret = AXIS_SELF;
8425 break;
8426 }
8427 return(ret);
8428}
8429
8430/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008431 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008432 * @ctxt: the XPath Parser context
8433 *
8434 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8435 * | AbbreviatedStep
8436 *
8437 * [12] AbbreviatedStep ::= '.' | '..'
8438 *
8439 * [5] AxisSpecifier ::= AxisName '::'
8440 * | AbbreviatedAxisSpecifier
8441 *
8442 * [13] AbbreviatedAxisSpecifier ::= '@'?
8443 *
8444 * Modified for XPtr range support as:
8445 *
8446 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8447 * | AbbreviatedStep
8448 * | 'range-to' '(' Expr ')' Predicate*
8449 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008450 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008451 * A location step of . is short for self::node(). This is
8452 * particularly useful in conjunction with //. For example, the
8453 * location path .//para is short for
8454 * self::node()/descendant-or-self::node()/child::para
8455 * and so will select all para descendant elements of the context
8456 * node.
8457 * Similarly, a location step of .. is short for parent::node().
8458 * For example, ../title is short for parent::node()/child::title
8459 * and so will select the title children of the parent of the context
8460 * node.
8461 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008462static void
8463xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008464#ifdef LIBXML_XPTR_ENABLED
8465 int rangeto = 0;
8466 int op2 = -1;
8467#endif
8468
Owen Taylor3473f882001-02-23 17:55:21 +00008469 SKIP_BLANKS;
8470 if ((CUR == '.') && (NXT(1) == '.')) {
8471 SKIP(2);
8472 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008473 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8474 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008475 } else if (CUR == '.') {
8476 NEXT;
8477 SKIP_BLANKS;
8478 } else {
8479 xmlChar *name = NULL;
8480 const xmlChar *prefix = NULL;
8481 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008482 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008483 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008484 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008485
8486 /*
8487 * The modification needed for XPointer change to the production
8488 */
8489#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008490 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008491 name = xmlXPathParseNCName(ctxt);
8492 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008493 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008494 xmlFree(name);
8495 SKIP_BLANKS;
8496 if (CUR != '(') {
8497 XP_ERROR(XPATH_EXPR_ERROR);
8498 }
8499 NEXT;
8500 SKIP_BLANKS;
8501
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008502 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008503 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008504 CHECK_ERROR;
8505
8506 SKIP_BLANKS;
8507 if (CUR != ')') {
8508 XP_ERROR(XPATH_EXPR_ERROR);
8509 }
8510 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008511 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008512 goto eval_predicates;
8513 }
8514 }
8515#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008516 if (CUR == '*') {
8517 axis = AXIS_CHILD;
8518 } else {
8519 if (name == NULL)
8520 name = xmlXPathParseNCName(ctxt);
8521 if (name != NULL) {
8522 axis = xmlXPathIsAxisName(name);
8523 if (axis != 0) {
8524 SKIP_BLANKS;
8525 if ((CUR == ':') && (NXT(1) == ':')) {
8526 SKIP(2);
8527 xmlFree(name);
8528 name = NULL;
8529 } else {
8530 /* an element name can conflict with an axis one :-\ */
8531 axis = AXIS_CHILD;
8532 }
Owen Taylor3473f882001-02-23 17:55:21 +00008533 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008534 axis = AXIS_CHILD;
8535 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008536 } else if (CUR == '@') {
8537 NEXT;
8538 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008539 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008540 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008541 }
Owen Taylor3473f882001-02-23 17:55:21 +00008542 }
8543
8544 CHECK_ERROR;
8545
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008546 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008547 if (test == 0)
8548 return;
8549
8550#ifdef DEBUG_STEP
8551 xmlGenericError(xmlGenericErrorContext,
8552 "Basis : computing new set\n");
8553#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008554
Owen Taylor3473f882001-02-23 17:55:21 +00008555#ifdef DEBUG_STEP
8556 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008557 if (ctxt->value == NULL)
8558 xmlGenericError(xmlGenericErrorContext, "no value\n");
8559 else if (ctxt->value->nodesetval == NULL)
8560 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8561 else
8562 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008563#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008564
8565eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008566 op1 = ctxt->comp->last;
8567 ctxt->comp->last = -1;
8568
Owen Taylor3473f882001-02-23 17:55:21 +00008569 SKIP_BLANKS;
8570 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008571 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008572 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008573
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008574#ifdef LIBXML_XPTR_ENABLED
8575 if (rangeto) {
8576 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8577 } else
8578#endif
8579 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8580 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008581
Owen Taylor3473f882001-02-23 17:55:21 +00008582 }
8583#ifdef DEBUG_STEP
8584 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008585 if (ctxt->value == NULL)
8586 xmlGenericError(xmlGenericErrorContext, "no value\n");
8587 else if (ctxt->value->nodesetval == NULL)
8588 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8589 else
8590 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8591 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008592#endif
8593}
8594
8595/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008596 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008597 * @ctxt: the XPath Parser context
8598 *
8599 * [3] RelativeLocationPath ::= Step
8600 * | RelativeLocationPath '/' Step
8601 * | AbbreviatedRelativeLocationPath
8602 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8603 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008604 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008605 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008606static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008607xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008608(xmlXPathParserContextPtr ctxt) {
8609 SKIP_BLANKS;
8610 if ((CUR == '/') && (NXT(1) == '/')) {
8611 SKIP(2);
8612 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008613 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8614 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008615 } else if (CUR == '/') {
8616 NEXT;
8617 SKIP_BLANKS;
8618 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008619 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008620 SKIP_BLANKS;
8621 while (CUR == '/') {
8622 if ((CUR == '/') && (NXT(1) == '/')) {
8623 SKIP(2);
8624 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008625 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008626 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008627 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008628 } else if (CUR == '/') {
8629 NEXT;
8630 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008631 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008632 }
8633 SKIP_BLANKS;
8634 }
8635}
8636
8637/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008638 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008639 * @ctxt: the XPath Parser context
8640 *
8641 * [1] LocationPath ::= RelativeLocationPath
8642 * | AbsoluteLocationPath
8643 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8644 * | AbbreviatedAbsoluteLocationPath
8645 * [10] AbbreviatedAbsoluteLocationPath ::=
8646 * '//' RelativeLocationPath
8647 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008648 * Compile a location path
8649 *
Owen Taylor3473f882001-02-23 17:55:21 +00008650 * // is short for /descendant-or-self::node()/. For example,
8651 * //para is short for /descendant-or-self::node()/child::para and
8652 * so will select any para element in the document (even a para element
8653 * that is a document element will be selected by //para since the
8654 * document element node is a child of the root node); div//para is
8655 * short for div/descendant-or-self::node()/child::para and so will
8656 * select all para descendants of div children.
8657 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008658static void
8659xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008660 SKIP_BLANKS;
8661 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008662 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008663 } else {
8664 while (CUR == '/') {
8665 if ((CUR == '/') && (NXT(1) == '/')) {
8666 SKIP(2);
8667 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008668 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8669 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008670 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008671 } else if (CUR == '/') {
8672 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008673 SKIP_BLANKS;
8674 if ((CUR != 0 ) &&
8675 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
8676 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008677 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008678 }
8679 }
8680 }
8681}
8682
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008683/************************************************************************
8684 * *
8685 * XPath precompiled expression evaluation *
8686 * *
8687 ************************************************************************/
8688
Daniel Veillardf06307e2001-07-03 10:35:50 +00008689static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008690xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8691
8692/**
8693 * xmlXPathNodeCollectAndTest:
8694 * @ctxt: the XPath Parser context
8695 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008696 * @first: pointer to the first element in document order
8697 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008698 *
8699 * This is the function implementing a step: based on the current list
8700 * of nodes, it builds up a new list, looking at all nodes under that
8701 * axis and selecting them it also do the predicate filtering
8702 *
8703 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00008704 *
8705 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008706 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008707static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008708xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008709 xmlXPathStepOpPtr op,
8710 xmlNodePtr * first, xmlNodePtr * last)
8711{
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008712 xmlXPathAxisVal axis = op->value;
8713 xmlXPathTestVal test = op->value2;
8714 xmlXPathTypeVal type = op->value3;
8715 const xmlChar *prefix = op->value4;
8716 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008717 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008718
8719#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008720 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008721#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008722 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008723 xmlNodeSetPtr ret, list;
8724 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008725 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00008726 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008727 xmlNodePtr cur = NULL;
8728 xmlXPathObjectPtr obj;
8729 xmlNodeSetPtr nodelist;
8730 xmlNodePtr tmp;
8731
Daniel Veillardf06307e2001-07-03 10:35:50 +00008732 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008733 obj = valuePop(ctxt);
8734 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00008735 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008736 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008737 URI = xmlXPathNsLookup(ctxt->context, prefix);
8738 if (URI == NULL)
8739 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008740 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008741#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008742 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008743#endif
8744 switch (axis) {
8745 case AXIS_ANCESTOR:
8746#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008747 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008748#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008749 first = NULL;
8750 next = xmlXPathNextAncestor;
8751 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008752 case AXIS_ANCESTOR_OR_SELF:
8753#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008754 xmlGenericError(xmlGenericErrorContext,
8755 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008756#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008757 first = NULL;
8758 next = xmlXPathNextAncestorOrSelf;
8759 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008760 case AXIS_ATTRIBUTE:
8761#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008762 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008763#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008764 first = NULL;
8765 last = NULL;
8766 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00008767 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008768 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008769 case AXIS_CHILD:
8770#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008771 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008772#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008773 last = NULL;
8774 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00008775 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008776 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008777 case AXIS_DESCENDANT:
8778#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008779 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008780#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008781 last = NULL;
8782 next = xmlXPathNextDescendant;
8783 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008784 case AXIS_DESCENDANT_OR_SELF:
8785#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008786 xmlGenericError(xmlGenericErrorContext,
8787 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008788#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008789 last = NULL;
8790 next = xmlXPathNextDescendantOrSelf;
8791 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008792 case AXIS_FOLLOWING:
8793#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008794 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008795#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008796 last = NULL;
8797 next = xmlXPathNextFollowing;
8798 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008799 case AXIS_FOLLOWING_SIBLING:
8800#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008801 xmlGenericError(xmlGenericErrorContext,
8802 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008803#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008804 last = NULL;
8805 next = xmlXPathNextFollowingSibling;
8806 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008807 case AXIS_NAMESPACE:
8808#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008809 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008810#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008811 first = NULL;
8812 last = NULL;
8813 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00008814 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008815 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008816 case AXIS_PARENT:
8817#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008818 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008819#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008820 first = NULL;
8821 next = xmlXPathNextParent;
8822 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008823 case AXIS_PRECEDING:
8824#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008825 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008826#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008827 first = NULL;
8828 next = xmlXPathNextPrecedingInternal;
8829 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008830 case AXIS_PRECEDING_SIBLING:
8831#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008832 xmlGenericError(xmlGenericErrorContext,
8833 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008834#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008835 first = NULL;
8836 next = xmlXPathNextPrecedingSibling;
8837 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008838 case AXIS_SELF:
8839#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008840 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008841#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008842 first = NULL;
8843 last = NULL;
8844 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00008845 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008846 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008847 }
8848 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008849 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008850
8851 nodelist = obj->nodesetval;
8852 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008853 xmlXPathFreeObject(obj);
8854 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8855 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008856 }
8857 addNode = xmlXPathNodeSetAddUnique;
8858 ret = NULL;
8859#ifdef DEBUG_STEP
8860 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008861 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008862 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008863 case NODE_TEST_NONE:
8864 xmlGenericError(xmlGenericErrorContext,
8865 " searching for none !!!\n");
8866 break;
8867 case NODE_TEST_TYPE:
8868 xmlGenericError(xmlGenericErrorContext,
8869 " searching for type %d\n", type);
8870 break;
8871 case NODE_TEST_PI:
8872 xmlGenericError(xmlGenericErrorContext,
8873 " searching for PI !!!\n");
8874 break;
8875 case NODE_TEST_ALL:
8876 xmlGenericError(xmlGenericErrorContext,
8877 " searching for *\n");
8878 break;
8879 case NODE_TEST_NS:
8880 xmlGenericError(xmlGenericErrorContext,
8881 " searching for namespace %s\n",
8882 prefix);
8883 break;
8884 case NODE_TEST_NAME:
8885 xmlGenericError(xmlGenericErrorContext,
8886 " searching for name %s\n", name);
8887 if (prefix != NULL)
8888 xmlGenericError(xmlGenericErrorContext,
8889 " with namespace %s\n", prefix);
8890 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008891 }
8892 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8893#endif
8894 /*
8895 * 2.3 Node Tests
8896 * - For the attribute axis, the principal node type is attribute.
8897 * - For the namespace axis, the principal node type is namespace.
8898 * - For other axes, the principal node type is element.
8899 *
8900 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008901 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008902 * select all element children of the context node
8903 */
8904 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008905 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008906 ctxt->context->node = nodelist->nodeTab[i];
8907
Daniel Veillardf06307e2001-07-03 10:35:50 +00008908 cur = NULL;
8909 list = xmlXPathNodeSetCreate(NULL);
8910 do {
8911 cur = next(ctxt, cur);
8912 if (cur == NULL)
8913 break;
8914 if ((first != NULL) && (*first == cur))
8915 break;
8916 if (((t % 256) == 0) &&
8917 (first != NULL) && (*first != NULL) &&
8918 (xmlXPathCmpNodes(*first, cur) >= 0))
8919 break;
8920 if ((last != NULL) && (*last == cur))
8921 break;
8922 if (((t % 256) == 0) &&
8923 (last != NULL) && (*last != NULL) &&
8924 (xmlXPathCmpNodes(cur, *last) >= 0))
8925 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008926 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008927#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008928 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
8929#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008930 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008931 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008932 ctxt->context->node = tmp;
8933 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008934 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008935 if ((cur->type == type) ||
8936 ((type == NODE_TYPE_NODE) &&
8937 ((cur->type == XML_DOCUMENT_NODE) ||
8938 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8939 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00008940 (cur->type == XML_NAMESPACE_DECL) ||
8941 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00008942 (cur->type == XML_PI_NODE) ||
8943 (cur->type == XML_COMMENT_NODE) ||
8944 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00008945 (cur->type == XML_TEXT_NODE))) ||
8946 ((type == NODE_TYPE_TEXT) &&
8947 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008948#ifdef DEBUG_STEP
8949 n++;
8950#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008951 addNode(list, cur);
8952 }
8953 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008954 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008955 if (cur->type == XML_PI_NODE) {
8956 if ((name != NULL) &&
8957 (!xmlStrEqual(name, cur->name)))
8958 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008959#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008960 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008961#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008962 addNode(list, cur);
8963 }
8964 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008965 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008966 if (axis == AXIS_ATTRIBUTE) {
8967 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008968#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008969 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008970#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008971 addNode(list, cur);
8972 }
8973 } else if (axis == AXIS_NAMESPACE) {
8974 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008975#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008976 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008977#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008978 xmlXPathNodeSetAddNs(list, ctxt->context->node,
8979 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008980 }
8981 } else {
8982 if (cur->type == XML_ELEMENT_NODE) {
8983 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008984#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008985 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008986#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008987 addNode(list, cur);
8988 } else if ((cur->ns != NULL) &&
8989 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008990#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008991 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008992#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008993 addNode(list, cur);
8994 }
8995 }
8996 }
8997 break;
8998 case NODE_TEST_NS:{
8999 TODO;
9000 break;
9001 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009002 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009003 switch (cur->type) {
9004 case XML_ELEMENT_NODE:
9005 if (xmlStrEqual(name, cur->name)) {
9006 if (prefix == NULL) {
9007 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009008#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009009 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009010#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009011 addNode(list, cur);
9012 }
9013 } else {
9014 if ((cur->ns != NULL) &&
9015 (xmlStrEqual(URI,
9016 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009017#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009018 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009019#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009020 addNode(list, cur);
9021 }
9022 }
9023 }
9024 break;
9025 case XML_ATTRIBUTE_NODE:{
9026 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009027
Daniel Veillardf06307e2001-07-03 10:35:50 +00009028 if (xmlStrEqual(name, attr->name)) {
9029 if (prefix == NULL) {
9030 if ((attr->ns == NULL) ||
9031 (attr->ns->prefix == NULL)) {
9032#ifdef DEBUG_STEP
9033 n++;
9034#endif
9035 addNode(list,
9036 (xmlNodePtr) attr);
9037 }
9038 } else {
9039 if ((attr->ns != NULL) &&
9040 (xmlStrEqual(URI,
9041 attr->ns->
9042 href))) {
9043#ifdef DEBUG_STEP
9044 n++;
9045#endif
9046 addNode(list,
9047 (xmlNodePtr) attr);
9048 }
9049 }
9050 }
9051 break;
9052 }
9053 case XML_NAMESPACE_DECL:
9054 if (cur->type == XML_NAMESPACE_DECL) {
9055 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009056
Daniel Veillardf06307e2001-07-03 10:35:50 +00009057 if ((ns->prefix != NULL) && (name != NULL)
9058 && (xmlStrEqual(ns->prefix, name))) {
9059#ifdef DEBUG_STEP
9060 n++;
9061#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009062 xmlXPathNodeSetAddNs(list,
9063 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009064 }
9065 }
9066 break;
9067 default:
9068 break;
9069 }
9070 break;
9071 break;
9072 }
9073 } while (cur != NULL);
9074
9075 /*
9076 * If there is some predicate filtering do it now
9077 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009078 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009079 xmlXPathObjectPtr obj2;
9080
9081 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9082 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9083 CHECK_TYPE0(XPATH_NODESET);
9084 obj2 = valuePop(ctxt);
9085 list = obj2->nodesetval;
9086 obj2->nodesetval = NULL;
9087 xmlXPathFreeObject(obj2);
9088 }
9089 if (ret == NULL) {
9090 ret = list;
9091 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009092 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009093 xmlXPathFreeNodeSet(list);
9094 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009095 }
9096 ctxt->context->node = tmp;
9097#ifdef DEBUG_STEP
9098 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009099 "\nExamined %d nodes, found %d nodes at that step\n",
9100 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009101#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009102 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009103 if ((obj->boolval) && (obj->user != NULL)) {
9104 ctxt->value->boolval = 1;
9105 ctxt->value->user = obj->user;
9106 obj->user = NULL;
9107 obj->boolval = 0;
9108 }
9109 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009110 return(t);
9111}
9112
9113/**
9114 * xmlXPathNodeCollectAndTestNth:
9115 * @ctxt: the XPath Parser context
9116 * @op: the XPath precompiled step operation
9117 * @indx: the index to collect
9118 * @first: pointer to the first element in document order
9119 * @last: pointer to the last element in document order
9120 *
9121 * This is the function implementing a step: based on the current list
9122 * of nodes, it builds up a new list, looking at all nodes under that
9123 * axis and selecting them it also do the predicate filtering
9124 *
9125 * Pushes the new NodeSet resulting from the search.
9126 * Returns the number of node traversed
9127 */
9128static int
9129xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9130 xmlXPathStepOpPtr op, int indx,
9131 xmlNodePtr * first, xmlNodePtr * last)
9132{
9133 xmlXPathAxisVal axis = op->value;
9134 xmlXPathTestVal test = op->value2;
9135 xmlXPathTypeVal type = op->value3;
9136 const xmlChar *prefix = op->value4;
9137 const xmlChar *name = op->value5;
9138 const xmlChar *URI = NULL;
9139 int n = 0, t = 0;
9140
9141 int i;
9142 xmlNodeSetPtr list;
9143 xmlXPathTraversalFunction next = NULL;
9144 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9145 xmlNodePtr cur = NULL;
9146 xmlXPathObjectPtr obj;
9147 xmlNodeSetPtr nodelist;
9148 xmlNodePtr tmp;
9149
9150 CHECK_TYPE0(XPATH_NODESET);
9151 obj = valuePop(ctxt);
9152 addNode = xmlXPathNodeSetAdd;
9153 if (prefix != NULL) {
9154 URI = xmlXPathNsLookup(ctxt->context, prefix);
9155 if (URI == NULL)
9156 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9157 }
9158#ifdef DEBUG_STEP_NTH
9159 xmlGenericError(xmlGenericErrorContext, "new step : ");
9160 if (first != NULL) {
9161 if (*first != NULL)
9162 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9163 (*first)->name);
9164 else
9165 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9166 }
9167 if (last != NULL) {
9168 if (*last != NULL)
9169 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9170 (*last)->name);
9171 else
9172 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9173 }
9174#endif
9175 switch (axis) {
9176 case AXIS_ANCESTOR:
9177#ifdef DEBUG_STEP_NTH
9178 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9179#endif
9180 first = NULL;
9181 next = xmlXPathNextAncestor;
9182 break;
9183 case AXIS_ANCESTOR_OR_SELF:
9184#ifdef DEBUG_STEP_NTH
9185 xmlGenericError(xmlGenericErrorContext,
9186 "axis 'ancestors-or-self' ");
9187#endif
9188 first = NULL;
9189 next = xmlXPathNextAncestorOrSelf;
9190 break;
9191 case AXIS_ATTRIBUTE:
9192#ifdef DEBUG_STEP_NTH
9193 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9194#endif
9195 first = NULL;
9196 last = NULL;
9197 next = xmlXPathNextAttribute;
9198 break;
9199 case AXIS_CHILD:
9200#ifdef DEBUG_STEP_NTH
9201 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9202#endif
9203 last = NULL;
9204 next = xmlXPathNextChild;
9205 break;
9206 case AXIS_DESCENDANT:
9207#ifdef DEBUG_STEP_NTH
9208 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9209#endif
9210 last = NULL;
9211 next = xmlXPathNextDescendant;
9212 break;
9213 case AXIS_DESCENDANT_OR_SELF:
9214#ifdef DEBUG_STEP_NTH
9215 xmlGenericError(xmlGenericErrorContext,
9216 "axis 'descendant-or-self' ");
9217#endif
9218 last = NULL;
9219 next = xmlXPathNextDescendantOrSelf;
9220 break;
9221 case AXIS_FOLLOWING:
9222#ifdef DEBUG_STEP_NTH
9223 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9224#endif
9225 last = NULL;
9226 next = xmlXPathNextFollowing;
9227 break;
9228 case AXIS_FOLLOWING_SIBLING:
9229#ifdef DEBUG_STEP_NTH
9230 xmlGenericError(xmlGenericErrorContext,
9231 "axis 'following-siblings' ");
9232#endif
9233 last = NULL;
9234 next = xmlXPathNextFollowingSibling;
9235 break;
9236 case AXIS_NAMESPACE:
9237#ifdef DEBUG_STEP_NTH
9238 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9239#endif
9240 last = NULL;
9241 first = NULL;
9242 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9243 break;
9244 case AXIS_PARENT:
9245#ifdef DEBUG_STEP_NTH
9246 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9247#endif
9248 first = NULL;
9249 next = xmlXPathNextParent;
9250 break;
9251 case AXIS_PRECEDING:
9252#ifdef DEBUG_STEP_NTH
9253 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9254#endif
9255 first = NULL;
9256 next = xmlXPathNextPrecedingInternal;
9257 break;
9258 case AXIS_PRECEDING_SIBLING:
9259#ifdef DEBUG_STEP_NTH
9260 xmlGenericError(xmlGenericErrorContext,
9261 "axis 'preceding-sibling' ");
9262#endif
9263 first = NULL;
9264 next = xmlXPathNextPrecedingSibling;
9265 break;
9266 case AXIS_SELF:
9267#ifdef DEBUG_STEP_NTH
9268 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9269#endif
9270 first = NULL;
9271 last = NULL;
9272 next = xmlXPathNextSelf;
9273 break;
9274 }
9275 if (next == NULL)
9276 return(0);
9277
9278 nodelist = obj->nodesetval;
9279 if (nodelist == NULL) {
9280 xmlXPathFreeObject(obj);
9281 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9282 return(0);
9283 }
9284 addNode = xmlXPathNodeSetAddUnique;
9285#ifdef DEBUG_STEP_NTH
9286 xmlGenericError(xmlGenericErrorContext,
9287 " context contains %d nodes\n", nodelist->nodeNr);
9288 switch (test) {
9289 case NODE_TEST_NONE:
9290 xmlGenericError(xmlGenericErrorContext,
9291 " searching for none !!!\n");
9292 break;
9293 case NODE_TEST_TYPE:
9294 xmlGenericError(xmlGenericErrorContext,
9295 " searching for type %d\n", type);
9296 break;
9297 case NODE_TEST_PI:
9298 xmlGenericError(xmlGenericErrorContext,
9299 " searching for PI !!!\n");
9300 break;
9301 case NODE_TEST_ALL:
9302 xmlGenericError(xmlGenericErrorContext,
9303 " searching for *\n");
9304 break;
9305 case NODE_TEST_NS:
9306 xmlGenericError(xmlGenericErrorContext,
9307 " searching for namespace %s\n",
9308 prefix);
9309 break;
9310 case NODE_TEST_NAME:
9311 xmlGenericError(xmlGenericErrorContext,
9312 " searching for name %s\n", name);
9313 if (prefix != NULL)
9314 xmlGenericError(xmlGenericErrorContext,
9315 " with namespace %s\n", prefix);
9316 break;
9317 }
9318 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9319#endif
9320 /*
9321 * 2.3 Node Tests
9322 * - For the attribute axis, the principal node type is attribute.
9323 * - For the namespace axis, the principal node type is namespace.
9324 * - For other axes, the principal node type is element.
9325 *
9326 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009327 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009328 * select all element children of the context node
9329 */
9330 tmp = ctxt->context->node;
9331 list = xmlXPathNodeSetCreate(NULL);
9332 for (i = 0; i < nodelist->nodeNr; i++) {
9333 ctxt->context->node = nodelist->nodeTab[i];
9334
9335 cur = NULL;
9336 n = 0;
9337 do {
9338 cur = next(ctxt, cur);
9339 if (cur == NULL)
9340 break;
9341 if ((first != NULL) && (*first == cur))
9342 break;
9343 if (((t % 256) == 0) &&
9344 (first != NULL) && (*first != NULL) &&
9345 (xmlXPathCmpNodes(*first, cur) >= 0))
9346 break;
9347 if ((last != NULL) && (*last == cur))
9348 break;
9349 if (((t % 256) == 0) &&
9350 (last != NULL) && (*last != NULL) &&
9351 (xmlXPathCmpNodes(cur, *last) >= 0))
9352 break;
9353 t++;
9354 switch (test) {
9355 case NODE_TEST_NONE:
9356 ctxt->context->node = tmp;
9357 STRANGE return(0);
9358 case NODE_TEST_TYPE:
9359 if ((cur->type == type) ||
9360 ((type == NODE_TYPE_NODE) &&
9361 ((cur->type == XML_DOCUMENT_NODE) ||
9362 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9363 (cur->type == XML_ELEMENT_NODE) ||
9364 (cur->type == XML_PI_NODE) ||
9365 (cur->type == XML_COMMENT_NODE) ||
9366 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +00009367 (cur->type == XML_TEXT_NODE))) ||
9368 ((type == NODE_TYPE_TEXT) &&
9369 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009370 n++;
9371 if (n == indx)
9372 addNode(list, cur);
9373 }
9374 break;
9375 case NODE_TEST_PI:
9376 if (cur->type == XML_PI_NODE) {
9377 if ((name != NULL) &&
9378 (!xmlStrEqual(name, cur->name)))
9379 break;
9380 n++;
9381 if (n == indx)
9382 addNode(list, cur);
9383 }
9384 break;
9385 case NODE_TEST_ALL:
9386 if (axis == AXIS_ATTRIBUTE) {
9387 if (cur->type == XML_ATTRIBUTE_NODE) {
9388 n++;
9389 if (n == indx)
9390 addNode(list, cur);
9391 }
9392 } else if (axis == AXIS_NAMESPACE) {
9393 if (cur->type == XML_NAMESPACE_DECL) {
9394 n++;
9395 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009396 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9397 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009398 }
9399 } else {
9400 if (cur->type == XML_ELEMENT_NODE) {
9401 if (prefix == NULL) {
9402 n++;
9403 if (n == indx)
9404 addNode(list, cur);
9405 } else if ((cur->ns != NULL) &&
9406 (xmlStrEqual(URI, cur->ns->href))) {
9407 n++;
9408 if (n == indx)
9409 addNode(list, cur);
9410 }
9411 }
9412 }
9413 break;
9414 case NODE_TEST_NS:{
9415 TODO;
9416 break;
9417 }
9418 case NODE_TEST_NAME:
9419 switch (cur->type) {
9420 case XML_ELEMENT_NODE:
9421 if (xmlStrEqual(name, cur->name)) {
9422 if (prefix == NULL) {
9423 if (cur->ns == NULL) {
9424 n++;
9425 if (n == indx)
9426 addNode(list, cur);
9427 }
9428 } else {
9429 if ((cur->ns != NULL) &&
9430 (xmlStrEqual(URI,
9431 cur->ns->href))) {
9432 n++;
9433 if (n == indx)
9434 addNode(list, cur);
9435 }
9436 }
9437 }
9438 break;
9439 case XML_ATTRIBUTE_NODE:{
9440 xmlAttrPtr attr = (xmlAttrPtr) cur;
9441
9442 if (xmlStrEqual(name, attr->name)) {
9443 if (prefix == NULL) {
9444 if ((attr->ns == NULL) ||
9445 (attr->ns->prefix == NULL)) {
9446 n++;
9447 if (n == indx)
9448 addNode(list, cur);
9449 }
9450 } else {
9451 if ((attr->ns != NULL) &&
9452 (xmlStrEqual(URI,
9453 attr->ns->
9454 href))) {
9455 n++;
9456 if (n == indx)
9457 addNode(list, cur);
9458 }
9459 }
9460 }
9461 break;
9462 }
9463 case XML_NAMESPACE_DECL:
9464 if (cur->type == XML_NAMESPACE_DECL) {
9465 xmlNsPtr ns = (xmlNsPtr) cur;
9466
9467 if ((ns->prefix != NULL) && (name != NULL)
9468 && (xmlStrEqual(ns->prefix, name))) {
9469 n++;
9470 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009471 xmlXPathNodeSetAddNs(list,
9472 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009473 }
9474 }
9475 break;
9476 default:
9477 break;
9478 }
9479 break;
9480 break;
9481 }
9482 } while (n < indx);
9483 }
9484 ctxt->context->node = tmp;
9485#ifdef DEBUG_STEP_NTH
9486 xmlGenericError(xmlGenericErrorContext,
9487 "\nExamined %d nodes, found %d nodes at that step\n",
9488 t, list->nodeNr);
9489#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009490 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009491 if ((obj->boolval) && (obj->user != NULL)) {
9492 ctxt->value->boolval = 1;
9493 ctxt->value->user = obj->user;
9494 obj->user = NULL;
9495 obj->boolval = 0;
9496 }
9497 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009498 return(t);
9499}
9500
9501/**
9502 * xmlXPathCompOpEvalFirst:
9503 * @ctxt: the XPath parser context with the compiled expression
9504 * @op: an XPath compiled operation
9505 * @first: the first elem found so far
9506 *
9507 * Evaluate the Precompiled XPath operation searching only the first
9508 * element in document order
9509 *
9510 * Returns the number of examined objects.
9511 */
9512static int
9513xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9514 xmlXPathStepOpPtr op, xmlNodePtr * first)
9515{
9516 int total = 0, cur;
9517 xmlXPathCompExprPtr comp;
9518 xmlXPathObjectPtr arg1, arg2;
9519
Daniel Veillard556c6682001-10-06 09:59:51 +00009520 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009521 comp = ctxt->comp;
9522 switch (op->op) {
9523 case XPATH_OP_END:
9524 return (0);
9525 case XPATH_OP_UNION:
9526 total =
9527 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9528 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009529 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009530 if ((ctxt->value != NULL)
9531 && (ctxt->value->type == XPATH_NODESET)
9532 && (ctxt->value->nodesetval != NULL)
9533 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9534 /*
9535 * limit tree traversing to first node in the result
9536 */
9537 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9538 *first = ctxt->value->nodesetval->nodeTab[0];
9539 }
9540 cur =
9541 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9542 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009543 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009544 CHECK_TYPE0(XPATH_NODESET);
9545 arg2 = valuePop(ctxt);
9546
9547 CHECK_TYPE0(XPATH_NODESET);
9548 arg1 = valuePop(ctxt);
9549
9550 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9551 arg2->nodesetval);
9552 valuePush(ctxt, arg1);
9553 xmlXPathFreeObject(arg2);
9554 /* optimizer */
9555 if (total > cur)
9556 xmlXPathCompSwap(op);
9557 return (total + cur);
9558 case XPATH_OP_ROOT:
9559 xmlXPathRoot(ctxt);
9560 return (0);
9561 case XPATH_OP_NODE:
9562 if (op->ch1 != -1)
9563 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009564 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009565 if (op->ch2 != -1)
9566 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009567 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009568 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9569 return (total);
9570 case XPATH_OP_RESET:
9571 if (op->ch1 != -1)
9572 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009573 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009574 if (op->ch2 != -1)
9575 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009576 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009577 ctxt->context->node = NULL;
9578 return (total);
9579 case XPATH_OP_COLLECT:{
9580 if (op->ch1 == -1)
9581 return (total);
9582
9583 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009584 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009585
9586 /*
9587 * Optimization for [n] selection where n is a number
9588 */
9589 if ((op->ch2 != -1) &&
9590 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9591 (comp->steps[op->ch2].ch1 == -1) &&
9592 (comp->steps[op->ch2].ch2 != -1) &&
9593 (comp->steps[comp->steps[op->ch2].ch2].op ==
9594 XPATH_OP_VALUE)) {
9595 xmlXPathObjectPtr val;
9596
9597 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9598 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9599 int indx = (int) val->floatval;
9600
9601 if (val->floatval == (float) indx) {
9602 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9603 first, NULL);
9604 return (total);
9605 }
9606 }
9607 }
9608 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9609 return (total);
9610 }
9611 case XPATH_OP_VALUE:
9612 valuePush(ctxt,
9613 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9614 return (0);
9615 case XPATH_OP_SORT:
9616 if (op->ch1 != -1)
9617 total +=
9618 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9619 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009620 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009621 if ((ctxt->value != NULL)
9622 && (ctxt->value->type == XPATH_NODESET)
9623 && (ctxt->value->nodesetval != NULL))
9624 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9625 return (total);
9626 default:
9627 return (xmlXPathCompOpEval(ctxt, op));
9628 }
9629}
9630
9631/**
9632 * xmlXPathCompOpEvalLast:
9633 * @ctxt: the XPath parser context with the compiled expression
9634 * @op: an XPath compiled operation
9635 * @last: the last elem found so far
9636 *
9637 * Evaluate the Precompiled XPath operation searching only the last
9638 * element in document order
9639 *
9640 * Returns the number of node traversed
9641 */
9642static int
9643xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9644 xmlNodePtr * last)
9645{
9646 int total = 0, cur;
9647 xmlXPathCompExprPtr comp;
9648 xmlXPathObjectPtr arg1, arg2;
9649
Daniel Veillard556c6682001-10-06 09:59:51 +00009650 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009651 comp = ctxt->comp;
9652 switch (op->op) {
9653 case XPATH_OP_END:
9654 return (0);
9655 case XPATH_OP_UNION:
9656 total =
9657 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009658 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009659 if ((ctxt->value != NULL)
9660 && (ctxt->value->type == XPATH_NODESET)
9661 && (ctxt->value->nodesetval != NULL)
9662 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9663 /*
9664 * limit tree traversing to first node in the result
9665 */
9666 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9667 *last =
9668 ctxt->value->nodesetval->nodeTab[ctxt->value->
9669 nodesetval->nodeNr -
9670 1];
9671 }
9672 cur =
9673 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009674 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009675 if ((ctxt->value != NULL)
9676 && (ctxt->value->type == XPATH_NODESET)
9677 && (ctxt->value->nodesetval != NULL)
9678 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9679 }
9680 CHECK_TYPE0(XPATH_NODESET);
9681 arg2 = valuePop(ctxt);
9682
9683 CHECK_TYPE0(XPATH_NODESET);
9684 arg1 = valuePop(ctxt);
9685
9686 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9687 arg2->nodesetval);
9688 valuePush(ctxt, arg1);
9689 xmlXPathFreeObject(arg2);
9690 /* optimizer */
9691 if (total > cur)
9692 xmlXPathCompSwap(op);
9693 return (total + cur);
9694 case XPATH_OP_ROOT:
9695 xmlXPathRoot(ctxt);
9696 return (0);
9697 case XPATH_OP_NODE:
9698 if (op->ch1 != -1)
9699 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009700 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009701 if (op->ch2 != -1)
9702 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009703 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009704 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9705 return (total);
9706 case XPATH_OP_RESET:
9707 if (op->ch1 != -1)
9708 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009709 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009710 if (op->ch2 != -1)
9711 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009712 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009713 ctxt->context->node = NULL;
9714 return (total);
9715 case XPATH_OP_COLLECT:{
9716 if (op->ch1 == -1)
9717 return (0);
9718
9719 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009720 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009721
9722 /*
9723 * Optimization for [n] selection where n is a number
9724 */
9725 if ((op->ch2 != -1) &&
9726 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9727 (comp->steps[op->ch2].ch1 == -1) &&
9728 (comp->steps[op->ch2].ch2 != -1) &&
9729 (comp->steps[comp->steps[op->ch2].ch2].op ==
9730 XPATH_OP_VALUE)) {
9731 xmlXPathObjectPtr val;
9732
9733 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9734 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9735 int indx = (int) val->floatval;
9736
9737 if (val->floatval == (float) indx) {
9738 total +=
9739 xmlXPathNodeCollectAndTestNth(ctxt, op,
9740 indx, NULL,
9741 last);
9742 return (total);
9743 }
9744 }
9745 }
9746 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9747 return (total);
9748 }
9749 case XPATH_OP_VALUE:
9750 valuePush(ctxt,
9751 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9752 return (0);
9753 case XPATH_OP_SORT:
9754 if (op->ch1 != -1)
9755 total +=
9756 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9757 last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009758 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009759 if ((ctxt->value != NULL)
9760 && (ctxt->value->type == XPATH_NODESET)
9761 && (ctxt->value->nodesetval != NULL))
9762 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9763 return (total);
9764 default:
9765 return (xmlXPathCompOpEval(ctxt, op));
9766 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009767}
9768
Owen Taylor3473f882001-02-23 17:55:21 +00009769/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009770 * xmlXPathCompOpEval:
9771 * @ctxt: the XPath parser context with the compiled expression
9772 * @op: an XPath compiled operation
9773 *
9774 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009775 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009776 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009777static int
9778xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9779{
9780 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009781 int equal, ret;
9782 xmlXPathCompExprPtr comp;
9783 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009784 xmlNodePtr bak;
9785 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +00009786 int pp;
William M. Brack692092b2002-06-28 15:01:24 +00009787 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009788
Daniel Veillard556c6682001-10-06 09:59:51 +00009789 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009790 comp = ctxt->comp;
9791 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009792 case XPATH_OP_END:
9793 return (0);
9794 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009795 bakd = ctxt->context->doc;
9796 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009797 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009798 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009799 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009800 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009801 xmlXPathBooleanFunction(ctxt, 1);
9802 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9803 return (total);
9804 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009805 ctxt->context->doc = bakd;
9806 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009807 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009808 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009809 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009810 if (ctxt->error) {
9811 xmlXPathFreeObject(arg2);
9812 return(0);
9813 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009814 xmlXPathBooleanFunction(ctxt, 1);
9815 arg1 = valuePop(ctxt);
9816 arg1->boolval &= arg2->boolval;
9817 valuePush(ctxt, arg1);
9818 xmlXPathFreeObject(arg2);
9819 return (total);
9820 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009821 bakd = ctxt->context->doc;
9822 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009823 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009824 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009825 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009826 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009827 xmlXPathBooleanFunction(ctxt, 1);
9828 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9829 return (total);
9830 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009831 ctxt->context->doc = bakd;
9832 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009833 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009834 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009835 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009836 if (ctxt->error) {
9837 xmlXPathFreeObject(arg2);
9838 return(0);
9839 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009840 xmlXPathBooleanFunction(ctxt, 1);
9841 arg1 = valuePop(ctxt);
9842 arg1->boolval |= arg2->boolval;
9843 valuePush(ctxt, arg1);
9844 xmlXPathFreeObject(arg2);
9845 return (total);
9846 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009847 bakd = ctxt->context->doc;
9848 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009849 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009850 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009851 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009852 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009853 ctxt->context->doc = bakd;
9854 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009855 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009856 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009857 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009858 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +00009859 if (op->value)
9860 equal = xmlXPathEqualValues(ctxt);
9861 else
9862 equal = xmlXPathNotEqualValues(ctxt);
9863 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +00009864 return (total);
9865 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009866 bakd = ctxt->context->doc;
9867 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009868 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009869 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009870 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009871 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009872 ctxt->context->doc = bakd;
9873 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009874 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009875 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009876 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009877 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009878 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
9879 valuePush(ctxt, xmlXPathNewBoolean(ret));
9880 return (total);
9881 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009882 bakd = ctxt->context->doc;
9883 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009884 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009885 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009886 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009887 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009888 if (op->ch2 != -1) {
9889 ctxt->context->doc = bakd;
9890 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009891 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009892 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009893 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009894 }
Daniel Veillard556c6682001-10-06 09:59:51 +00009895 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009896 if (op->value == 0)
9897 xmlXPathSubValues(ctxt);
9898 else if (op->value == 1)
9899 xmlXPathAddValues(ctxt);
9900 else if (op->value == 2)
9901 xmlXPathValueFlipSign(ctxt);
9902 else if (op->value == 3) {
9903 CAST_TO_NUMBER;
9904 CHECK_TYPE0(XPATH_NUMBER);
9905 }
9906 return (total);
9907 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009908 bakd = ctxt->context->doc;
9909 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009910 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009911 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009912 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009913 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009914 ctxt->context->doc = bakd;
9915 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009916 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009917 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009918 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009919 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009920 if (op->value == 0)
9921 xmlXPathMultValues(ctxt);
9922 else if (op->value == 1)
9923 xmlXPathDivValues(ctxt);
9924 else if (op->value == 2)
9925 xmlXPathModValues(ctxt);
9926 return (total);
9927 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009928 bakd = ctxt->context->doc;
9929 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009930 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009931 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009932 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009933 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009934 ctxt->context->doc = bakd;
9935 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009936 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009937 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009938 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009939 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009940 CHECK_TYPE0(XPATH_NODESET);
9941 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009942
Daniel Veillardf06307e2001-07-03 10:35:50 +00009943 CHECK_TYPE0(XPATH_NODESET);
9944 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009945
Daniel Veillardf06307e2001-07-03 10:35:50 +00009946 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9947 arg2->nodesetval);
9948 valuePush(ctxt, arg1);
9949 xmlXPathFreeObject(arg2);
9950 return (total);
9951 case XPATH_OP_ROOT:
9952 xmlXPathRoot(ctxt);
9953 return (total);
9954 case XPATH_OP_NODE:
9955 if (op->ch1 != -1)
9956 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009957 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009958 if (op->ch2 != -1)
9959 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009960 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009961 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9962 return (total);
9963 case XPATH_OP_RESET:
9964 if (op->ch1 != -1)
9965 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009966 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009967 if (op->ch2 != -1)
9968 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009969 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009970 ctxt->context->node = NULL;
9971 return (total);
9972 case XPATH_OP_COLLECT:{
9973 if (op->ch1 == -1)
9974 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009975
Daniel Veillardf06307e2001-07-03 10:35:50 +00009976 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009977 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009978
Daniel Veillardf06307e2001-07-03 10:35:50 +00009979 /*
9980 * Optimization for [n] selection where n is a number
9981 */
9982 if ((op->ch2 != -1) &&
9983 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9984 (comp->steps[op->ch2].ch1 == -1) &&
9985 (comp->steps[op->ch2].ch2 != -1) &&
9986 (comp->steps[comp->steps[op->ch2].ch2].op ==
9987 XPATH_OP_VALUE)) {
9988 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +00009989
Daniel Veillardf06307e2001-07-03 10:35:50 +00009990 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9991 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9992 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009993
Daniel Veillardf06307e2001-07-03 10:35:50 +00009994 if (val->floatval == (float) indx) {
9995 total +=
9996 xmlXPathNodeCollectAndTestNth(ctxt, op,
9997 indx, NULL,
9998 NULL);
9999 return (total);
10000 }
10001 }
10002 }
10003 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
10004 return (total);
10005 }
10006 case XPATH_OP_VALUE:
10007 valuePush(ctxt,
10008 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10009 return (total);
10010 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000010011 xmlXPathObjectPtr val;
10012
Daniel Veillardf06307e2001-07-03 10:35:50 +000010013 if (op->ch1 != -1)
10014 total +=
10015 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010016 if (op->value5 == NULL) {
10017 val = xmlXPathVariableLookup(ctxt->context, op->value4);
10018 if (val == NULL) {
10019 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10020 return(0);
10021 }
10022 valuePush(ctxt, val);
10023 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010024 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010025
Daniel Veillardf06307e2001-07-03 10:35:50 +000010026 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10027 if (URI == NULL) {
10028 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010029 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010030 op->value4, op->value5);
10031 return (total);
10032 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010033 val = xmlXPathVariableLookupNS(ctxt->context,
10034 op->value4, URI);
10035 if (val == NULL) {
10036 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10037 return(0);
10038 }
10039 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010040 }
10041 return (total);
10042 }
10043 case XPATH_OP_FUNCTION:{
10044 xmlXPathFunction func;
10045 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000010046 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010047
10048 if (op->ch1 != -1)
10049 total +=
10050 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010051 if (ctxt->valueNr < op->value) {
10052 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010053 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010054 ctxt->error = XPATH_INVALID_OPERAND;
10055 return (total);
10056 }
10057 for (i = 0; i < op->value; i++)
10058 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10059 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010060 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010061 ctxt->error = XPATH_INVALID_OPERAND;
10062 return (total);
10063 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010064 if (op->cache != NULL)
10065 func = (xmlXPathFunction) op->cache;
10066 else {
10067 const xmlChar *URI = NULL;
10068
10069 if (op->value5 == NULL)
10070 func =
10071 xmlXPathFunctionLookup(ctxt->context,
10072 op->value4);
10073 else {
10074 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10075 if (URI == NULL) {
10076 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010077 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010078 op->value4, op->value5);
10079 return (total);
10080 }
10081 func = xmlXPathFunctionLookupNS(ctxt->context,
10082 op->value4, URI);
10083 }
10084 if (func == NULL) {
10085 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010086 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010087 op->value4);
10088 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010089 }
10090 op->cache = (void *) func;
10091 op->cacheURI = (void *) URI;
10092 }
10093 oldFunc = ctxt->context->function;
10094 oldFuncURI = ctxt->context->functionURI;
10095 ctxt->context->function = op->value4;
10096 ctxt->context->functionURI = op->cacheURI;
10097 func(ctxt, op->value);
10098 ctxt->context->function = oldFunc;
10099 ctxt->context->functionURI = oldFuncURI;
10100 return (total);
10101 }
10102 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000010103 bakd = ctxt->context->doc;
10104 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010105 if (op->ch1 != -1)
10106 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010107 ctxt->context->doc = bakd;
10108 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010109 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010110 if (op->ch2 != -1)
10111 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010112 ctxt->context->doc = bakd;
10113 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010114 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010115 return (total);
10116 case XPATH_OP_PREDICATE:
10117 case XPATH_OP_FILTER:{
10118 xmlXPathObjectPtr res;
10119 xmlXPathObjectPtr obj, tmp;
10120 xmlNodeSetPtr newset = NULL;
10121 xmlNodeSetPtr oldset;
10122 xmlNodePtr oldnode;
10123 int i;
10124
10125 /*
10126 * Optimization for ()[1] selection i.e. the first elem
10127 */
10128 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10129 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10130 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10131 xmlXPathObjectPtr val;
10132
10133 val = comp->steps[op->ch2].value4;
10134 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10135 (val->floatval == 1.0)) {
10136 xmlNodePtr first = NULL;
10137
10138 total +=
10139 xmlXPathCompOpEvalFirst(ctxt,
10140 &comp->steps[op->ch1],
10141 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010142 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010143 /*
10144 * The nodeset should be in document order,
10145 * Keep only the first value
10146 */
10147 if ((ctxt->value != NULL) &&
10148 (ctxt->value->type == XPATH_NODESET) &&
10149 (ctxt->value->nodesetval != NULL) &&
10150 (ctxt->value->nodesetval->nodeNr > 1))
10151 ctxt->value->nodesetval->nodeNr = 1;
10152 return (total);
10153 }
10154 }
10155 /*
10156 * Optimization for ()[last()] selection i.e. the last elem
10157 */
10158 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10159 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10160 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10161 int f = comp->steps[op->ch2].ch1;
10162
10163 if ((f != -1) &&
10164 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10165 (comp->steps[f].value5 == NULL) &&
10166 (comp->steps[f].value == 0) &&
10167 (comp->steps[f].value4 != NULL) &&
10168 (xmlStrEqual
10169 (comp->steps[f].value4, BAD_CAST "last"))) {
10170 xmlNodePtr last = NULL;
10171
10172 total +=
10173 xmlXPathCompOpEvalLast(ctxt,
10174 &comp->steps[op->ch1],
10175 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010176 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010177 /*
10178 * The nodeset should be in document order,
10179 * Keep only the last value
10180 */
10181 if ((ctxt->value != NULL) &&
10182 (ctxt->value->type == XPATH_NODESET) &&
10183 (ctxt->value->nodesetval != NULL) &&
10184 (ctxt->value->nodesetval->nodeTab != NULL) &&
10185 (ctxt->value->nodesetval->nodeNr > 1)) {
10186 ctxt->value->nodesetval->nodeTab[0] =
10187 ctxt->value->nodesetval->nodeTab[ctxt->
10188 value->
10189 nodesetval->
10190 nodeNr -
10191 1];
10192 ctxt->value->nodesetval->nodeNr = 1;
10193 }
10194 return (total);
10195 }
10196 }
10197
10198 if (op->ch1 != -1)
10199 total +=
10200 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010201 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010202 if (op->ch2 == -1)
10203 return (total);
10204 if (ctxt->value == NULL)
10205 return (total);
10206
10207 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010208
10209#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010210 /*
10211 * Hum are we filtering the result of an XPointer expression
10212 */
10213 if (ctxt->value->type == XPATH_LOCATIONSET) {
10214 xmlLocationSetPtr newlocset = NULL;
10215 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010216
Daniel Veillardf06307e2001-07-03 10:35:50 +000010217 /*
10218 * Extract the old locset, and then evaluate the result of the
10219 * expression for all the element in the locset. use it to grow
10220 * up a new locset.
10221 */
10222 CHECK_TYPE0(XPATH_LOCATIONSET);
10223 obj = valuePop(ctxt);
10224 oldlocset = obj->user;
10225 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010226
Daniel Veillardf06307e2001-07-03 10:35:50 +000010227 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10228 ctxt->context->contextSize = 0;
10229 ctxt->context->proximityPosition = 0;
10230 if (op->ch2 != -1)
10231 total +=
10232 xmlXPathCompOpEval(ctxt,
10233 &comp->steps[op->ch2]);
10234 res = valuePop(ctxt);
10235 if (res != NULL)
10236 xmlXPathFreeObject(res);
10237 valuePush(ctxt, obj);
10238 CHECK_ERROR0;
10239 return (total);
10240 }
10241 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010242
Daniel Veillardf06307e2001-07-03 10:35:50 +000010243 for (i = 0; i < oldlocset->locNr; i++) {
10244 /*
10245 * Run the evaluation with a node list made of a
10246 * single item in the nodelocset.
10247 */
10248 ctxt->context->node = oldlocset->locTab[i]->user;
10249 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10250 valuePush(ctxt, tmp);
10251 ctxt->context->contextSize = oldlocset->locNr;
10252 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010253
Daniel Veillardf06307e2001-07-03 10:35:50 +000010254 if (op->ch2 != -1)
10255 total +=
10256 xmlXPathCompOpEval(ctxt,
10257 &comp->steps[op->ch2]);
10258 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010259
Daniel Veillardf06307e2001-07-03 10:35:50 +000010260 /*
10261 * The result of the evaluation need to be tested to
10262 * decided whether the filter succeeded or not
10263 */
10264 res = valuePop(ctxt);
10265 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10266 xmlXPtrLocationSetAdd(newlocset,
10267 xmlXPathObjectCopy
10268 (oldlocset->locTab[i]));
10269 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010270
Daniel Veillardf06307e2001-07-03 10:35:50 +000010271 /*
10272 * Cleanup
10273 */
10274 if (res != NULL)
10275 xmlXPathFreeObject(res);
10276 if (ctxt->value == tmp) {
10277 res = valuePop(ctxt);
10278 xmlXPathFreeObject(res);
10279 }
10280
10281 ctxt->context->node = NULL;
10282 }
10283
10284 /*
10285 * The result is used as the new evaluation locset.
10286 */
10287 xmlXPathFreeObject(obj);
10288 ctxt->context->node = NULL;
10289 ctxt->context->contextSize = -1;
10290 ctxt->context->proximityPosition = -1;
10291 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10292 ctxt->context->node = oldnode;
10293 return (total);
10294 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010295#endif /* LIBXML_XPTR_ENABLED */
10296
Daniel Veillardf06307e2001-07-03 10:35:50 +000010297 /*
10298 * Extract the old set, and then evaluate the result of the
10299 * expression for all the element in the set. use it to grow
10300 * up a new set.
10301 */
10302 CHECK_TYPE0(XPATH_NODESET);
10303 obj = valuePop(ctxt);
10304 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010305
Daniel Veillardf06307e2001-07-03 10:35:50 +000010306 oldnode = ctxt->context->node;
10307 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010308
Daniel Veillardf06307e2001-07-03 10:35:50 +000010309 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10310 ctxt->context->contextSize = 0;
10311 ctxt->context->proximityPosition = 0;
10312 if (op->ch2 != -1)
10313 total +=
10314 xmlXPathCompOpEval(ctxt,
10315 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010316 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010317 res = valuePop(ctxt);
10318 if (res != NULL)
10319 xmlXPathFreeObject(res);
10320 valuePush(ctxt, obj);
10321 ctxt->context->node = oldnode;
10322 CHECK_ERROR0;
10323 } else {
10324 /*
10325 * Initialize the new set.
10326 */
10327 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010328
Daniel Veillardf06307e2001-07-03 10:35:50 +000010329 for (i = 0; i < oldset->nodeNr; i++) {
10330 /*
10331 * Run the evaluation with a node list made of
10332 * a single item in the nodeset.
10333 */
10334 ctxt->context->node = oldset->nodeTab[i];
10335 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10336 valuePush(ctxt, tmp);
10337 ctxt->context->contextSize = oldset->nodeNr;
10338 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010339
Daniel Veillardf06307e2001-07-03 10:35:50 +000010340 if (op->ch2 != -1)
10341 total +=
10342 xmlXPathCompOpEval(ctxt,
10343 &comp->steps[op->ch2]);
10344 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010345
Daniel Veillardf06307e2001-07-03 10:35:50 +000010346 /*
10347 * The result of the evaluation need to be tested to
10348 * decided whether the filter succeeded or not
10349 */
10350 res = valuePop(ctxt);
10351 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10352 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10353 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010354
Daniel Veillardf06307e2001-07-03 10:35:50 +000010355 /*
10356 * Cleanup
10357 */
10358 if (res != NULL)
10359 xmlXPathFreeObject(res);
10360 if (ctxt->value == tmp) {
10361 res = valuePop(ctxt);
10362 xmlXPathFreeObject(res);
10363 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010364
Daniel Veillardf06307e2001-07-03 10:35:50 +000010365 ctxt->context->node = NULL;
10366 }
10367
10368 /*
10369 * The result is used as the new evaluation set.
10370 */
10371 xmlXPathFreeObject(obj);
10372 ctxt->context->node = NULL;
10373 ctxt->context->contextSize = -1;
10374 ctxt->context->proximityPosition = -1;
10375 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10376 }
10377 ctxt->context->node = oldnode;
10378 return (total);
10379 }
10380 case XPATH_OP_SORT:
10381 if (op->ch1 != -1)
10382 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010383 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010384 if ((ctxt->value != NULL) &&
10385 (ctxt->value->type == XPATH_NODESET) &&
10386 (ctxt->value->nodesetval != NULL))
10387 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10388 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010389#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010390 case XPATH_OP_RANGETO:{
10391 xmlXPathObjectPtr range;
10392 xmlXPathObjectPtr res, obj;
10393 xmlXPathObjectPtr tmp;
10394 xmlLocationSetPtr newset = NULL;
10395 xmlNodeSetPtr oldset;
10396 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010397
Daniel Veillardf06307e2001-07-03 10:35:50 +000010398 if (op->ch1 != -1)
10399 total +=
10400 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10401 if (op->ch2 == -1)
10402 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010403
Daniel Veillardf06307e2001-07-03 10:35:50 +000010404 CHECK_TYPE0(XPATH_NODESET);
10405 obj = valuePop(ctxt);
10406 oldset = obj->nodesetval;
10407 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010408
Daniel Veillardf06307e2001-07-03 10:35:50 +000010409 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010410
Daniel Veillardf06307e2001-07-03 10:35:50 +000010411 if (oldset != NULL) {
10412 for (i = 0; i < oldset->nodeNr; i++) {
10413 /*
10414 * Run the evaluation with a node list made of a single item
10415 * in the nodeset.
10416 */
10417 ctxt->context->node = oldset->nodeTab[i];
10418 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10419 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010420
Daniel Veillardf06307e2001-07-03 10:35:50 +000010421 if (op->ch2 != -1)
10422 total +=
10423 xmlXPathCompOpEval(ctxt,
10424 &comp->steps[op->ch2]);
10425 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010426
Daniel Veillardf06307e2001-07-03 10:35:50 +000010427 /*
10428 * The result of the evaluation need to be tested to
10429 * decided whether the filter succeeded or not
10430 */
10431 res = valuePop(ctxt);
10432 range =
10433 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10434 res);
10435 if (range != NULL) {
10436 xmlXPtrLocationSetAdd(newset, range);
10437 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010438
Daniel Veillardf06307e2001-07-03 10:35:50 +000010439 /*
10440 * Cleanup
10441 */
10442 if (res != NULL)
10443 xmlXPathFreeObject(res);
10444 if (ctxt->value == tmp) {
10445 res = valuePop(ctxt);
10446 xmlXPathFreeObject(res);
10447 }
10448
10449 ctxt->context->node = NULL;
10450 }
10451 }
10452
10453 /*
10454 * The result is used as the new evaluation set.
10455 */
10456 xmlXPathFreeObject(obj);
10457 ctxt->context->node = NULL;
10458 ctxt->context->contextSize = -1;
10459 ctxt->context->proximityPosition = -1;
10460 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
10461 return (total);
10462 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010463#endif /* LIBXML_XPTR_ENABLED */
10464 }
10465 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010466 "XPath: unknown precompiled operation %d\n", op->op);
10467 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010468}
10469
10470/**
10471 * xmlXPathRunEval:
10472 * @ctxt: the XPath parser context with the compiled expression
10473 *
10474 * Evaluate the Precompiled XPath expression in the given context.
10475 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010476static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010477xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10478 xmlXPathCompExprPtr comp;
10479
10480 if ((ctxt == NULL) || (ctxt->comp == NULL))
10481 return;
10482
10483 if (ctxt->valueTab == NULL) {
10484 /* Allocate the value stack */
10485 ctxt->valueTab = (xmlXPathObjectPtr *)
10486 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10487 if (ctxt->valueTab == NULL) {
10488 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010489 }
10490 ctxt->valueNr = 0;
10491 ctxt->valueMax = 10;
10492 ctxt->value = NULL;
10493 }
10494 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000010495 if(comp->last < 0) {
10496 xmlGenericError(xmlGenericErrorContext,
10497 "xmlXPathRunEval: last is less than zero\n");
10498 return;
10499 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010500 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10501}
10502
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010503/************************************************************************
10504 * *
10505 * Public interfaces *
10506 * *
10507 ************************************************************************/
10508
10509/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010510 * xmlXPathEvalPredicate:
10511 * @ctxt: the XPath context
10512 * @res: the Predicate Expression evaluation result
10513 *
10514 * Evaluate a predicate result for the current node.
10515 * A PredicateExpr is evaluated by evaluating the Expr and converting
10516 * the result to a boolean. If the result is a number, the result will
10517 * be converted to true if the number is equal to the position of the
10518 * context node in the context node list (as returned by the position
10519 * function) and will be converted to false otherwise; if the result
10520 * is not a number, then the result will be converted as if by a call
10521 * to the boolean function.
10522 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010523 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010524 */
10525int
10526xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
10527 if (res == NULL) return(0);
10528 switch (res->type) {
10529 case XPATH_BOOLEAN:
10530 return(res->boolval);
10531 case XPATH_NUMBER:
10532 return(res->floatval == ctxt->proximityPosition);
10533 case XPATH_NODESET:
10534 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010535 if (res->nodesetval == NULL)
10536 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010537 return(res->nodesetval->nodeNr != 0);
10538 case XPATH_STRING:
10539 return((res->stringval != NULL) &&
10540 (xmlStrlen(res->stringval) != 0));
10541 default:
10542 STRANGE
10543 }
10544 return(0);
10545}
10546
10547/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010548 * xmlXPathEvaluatePredicateResult:
10549 * @ctxt: the XPath Parser context
10550 * @res: the Predicate Expression evaluation result
10551 *
10552 * Evaluate a predicate result for the current node.
10553 * A PredicateExpr is evaluated by evaluating the Expr and converting
10554 * the result to a boolean. If the result is a number, the result will
10555 * be converted to true if the number is equal to the position of the
10556 * context node in the context node list (as returned by the position
10557 * function) and will be converted to false otherwise; if the result
10558 * is not a number, then the result will be converted as if by a call
10559 * to the boolean function.
10560 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010561 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010562 */
10563int
10564xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10565 xmlXPathObjectPtr res) {
10566 if (res == NULL) return(0);
10567 switch (res->type) {
10568 case XPATH_BOOLEAN:
10569 return(res->boolval);
10570 case XPATH_NUMBER:
10571 return(res->floatval == ctxt->context->proximityPosition);
10572 case XPATH_NODESET:
10573 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000010574 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000010575 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010576 return(res->nodesetval->nodeNr != 0);
10577 case XPATH_STRING:
10578 return((res->stringval != NULL) &&
10579 (xmlStrlen(res->stringval) != 0));
10580 default:
10581 STRANGE
10582 }
10583 return(0);
10584}
10585
10586/**
10587 * xmlXPathCompile:
10588 * @str: the XPath expression
10589 *
10590 * Compile an XPath expression
10591 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010592 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010593 * the caller has to free the object.
10594 */
10595xmlXPathCompExprPtr
10596xmlXPathCompile(const xmlChar *str) {
10597 xmlXPathParserContextPtr ctxt;
10598 xmlXPathCompExprPtr comp;
10599
10600 xmlXPathInit();
10601
10602 ctxt = xmlXPathNewParserContext(str, NULL);
10603 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010604
Daniel Veillard40af6492001-04-22 08:50:55 +000010605 if (*ctxt->cur != 0) {
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010606 /*
10607 * aleksey: in some cases this line prints *second* error message
10608 * (see bug #78858) and probably this should be fixed.
10609 * However, we are not sure that all error messages are printed
10610 * out in other places. It's not critical so we leave it as-is for now
10611 */
Daniel Veillard40af6492001-04-22 08:50:55 +000010612 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10613 comp = NULL;
10614 } else {
10615 comp = ctxt->comp;
10616 ctxt->comp = NULL;
10617 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010618 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010619 if (comp != NULL) {
Daniel Veillardceb09b92002-10-04 11:46:37 +000010620 comp->expr = xmlStrdup(str);
10621#ifdef DEBUG_EVAL_COUNTS
Daniel Veillardf06307e2001-07-03 10:35:50 +000010622 comp->string = xmlStrdup(str);
10623 comp->nb = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010624#endif
Daniel Veillardceb09b92002-10-04 11:46:37 +000010625 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010626 return(comp);
10627}
10628
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010629/**
10630 * xmlXPathCompiledEval:
10631 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000010632 * @ctx: the XPath context
10633 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010634 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000010635 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010636 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000010637 * the caller has to free the object.
10638 */
10639xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010640xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000010641 xmlXPathParserContextPtr ctxt;
10642 xmlXPathObjectPtr res, tmp, init = NULL;
10643 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000010644#ifndef LIBXML_THREAD_ENABLED
10645 static int reentance = 0;
10646#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010647
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010648 if ((comp == NULL) || (ctx == NULL))
10649 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010650 xmlXPathInit();
10651
10652 CHECK_CONTEXT(ctx)
10653
Daniel Veillard81463942001-10-16 12:34:39 +000010654#ifndef LIBXML_THREAD_ENABLED
10655 reentance++;
10656 if (reentance > 1)
10657 xmlXPathDisableOptimizer = 1;
10658#endif
10659
Daniel Veillardf06307e2001-07-03 10:35:50 +000010660#ifdef DEBUG_EVAL_COUNTS
10661 comp->nb++;
10662 if ((comp->string != NULL) && (comp->nb > 100)) {
10663 fprintf(stderr, "100 x %s\n", comp->string);
10664 comp->nb = 0;
10665 }
10666#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010667 ctxt = xmlXPathCompParserContext(comp, ctx);
10668 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010669
10670 if (ctxt->value == NULL) {
10671 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010672 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000010673 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000010674 } else {
10675 res = valuePop(ctxt);
10676 }
10677
Daniel Veillardf06307e2001-07-03 10:35:50 +000010678
Owen Taylor3473f882001-02-23 17:55:21 +000010679 do {
10680 tmp = valuePop(ctxt);
10681 if (tmp != NULL) {
10682 if (tmp != init)
10683 stack++;
10684 xmlXPathFreeObject(tmp);
10685 }
10686 } while (tmp != NULL);
10687 if ((stack != 0) && (res != NULL)) {
10688 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010689 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000010690 stack);
10691 }
10692 if (ctxt->error != XPATH_EXPRESSION_OK) {
10693 xmlXPathFreeObject(res);
10694 res = NULL;
10695 }
10696
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010697
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010698 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010699 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000010700#ifndef LIBXML_THREAD_ENABLED
10701 reentance--;
10702#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010703 return(res);
10704}
10705
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010706/**
10707 * xmlXPathEvalExpr:
10708 * @ctxt: the XPath Parser context
10709 *
10710 * Parse and evaluate an XPath expression in the given context,
10711 * then push the result on the context stack
10712 */
10713void
10714xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
10715 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010716 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010717 xmlXPathRunEval(ctxt);
10718}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010719
10720/**
10721 * xmlXPathEval:
10722 * @str: the XPath expression
10723 * @ctx: the XPath context
10724 *
10725 * Evaluate the XPath Location Path in the given context.
10726 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010727 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010728 * the caller has to free the object.
10729 */
10730xmlXPathObjectPtr
10731xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
10732 xmlXPathParserContextPtr ctxt;
10733 xmlXPathObjectPtr res, tmp, init = NULL;
10734 int stack = 0;
10735
10736 xmlXPathInit();
10737
10738 CHECK_CONTEXT(ctx)
10739
10740 ctxt = xmlXPathNewParserContext(str, ctx);
10741 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010742
10743 if (ctxt->value == NULL) {
10744 xmlGenericError(xmlGenericErrorContext,
10745 "xmlXPathEval: evaluation failed\n");
10746 res = NULL;
10747 } else if (*ctxt->cur != 0) {
10748 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10749 res = NULL;
10750 } else {
10751 res = valuePop(ctxt);
10752 }
10753
10754 do {
10755 tmp = valuePop(ctxt);
10756 if (tmp != NULL) {
10757 if (tmp != init)
10758 stack++;
10759 xmlXPathFreeObject(tmp);
10760 }
10761 } while (tmp != NULL);
10762 if ((stack != 0) && (res != NULL)) {
10763 xmlGenericError(xmlGenericErrorContext,
10764 "xmlXPathEval: %d object left on the stack\n",
10765 stack);
10766 }
10767 if (ctxt->error != XPATH_EXPRESSION_OK) {
10768 xmlXPathFreeObject(res);
10769 res = NULL;
10770 }
10771
Owen Taylor3473f882001-02-23 17:55:21 +000010772 xmlXPathFreeParserContext(ctxt);
10773 return(res);
10774}
10775
10776/**
10777 * xmlXPathEvalExpression:
10778 * @str: the XPath expression
10779 * @ctxt: the XPath context
10780 *
10781 * Evaluate the XPath expression in the given context.
10782 *
10783 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
10784 * the caller has to free the object.
10785 */
10786xmlXPathObjectPtr
10787xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
10788 xmlXPathParserContextPtr pctxt;
10789 xmlXPathObjectPtr res, tmp;
10790 int stack = 0;
10791
10792 xmlXPathInit();
10793
10794 CHECK_CONTEXT(ctxt)
10795
10796 pctxt = xmlXPathNewParserContext(str, ctxt);
10797 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010798
10799 if (*pctxt->cur != 0) {
10800 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10801 res = NULL;
10802 } else {
10803 res = valuePop(pctxt);
10804 }
10805 do {
10806 tmp = valuePop(pctxt);
10807 if (tmp != NULL) {
10808 xmlXPathFreeObject(tmp);
10809 stack++;
10810 }
10811 } while (tmp != NULL);
10812 if ((stack != 0) && (res != NULL)) {
10813 xmlGenericError(xmlGenericErrorContext,
10814 "xmlXPathEvalExpression: %d object left on the stack\n",
10815 stack);
10816 }
10817 xmlXPathFreeParserContext(pctxt);
10818 return(res);
10819}
10820
Daniel Veillard42766c02002-08-22 20:52:17 +000010821/************************************************************************
10822 * *
10823 * Extra functions not pertaining to the XPath spec *
10824 * *
10825 ************************************************************************/
10826/**
10827 * xmlXPathEscapeUriFunction:
10828 * @ctxt: the XPath Parser context
10829 * @nargs: the number of arguments
10830 *
10831 * Implement the escape-uri() XPath function
10832 * string escape-uri(string $str, bool $escape-reserved)
10833 *
10834 * This function applies the URI escaping rules defined in section 2 of [RFC
10835 * 2396] to the string supplied as $uri-part, which typically represents all
10836 * or part of a URI. The effect of the function is to replace any special
10837 * character in the string by an escape sequence of the form %xx%yy...,
10838 * where xxyy... is the hexadecimal representation of the octets used to
10839 * represent the character in UTF-8.
10840 *
10841 * The set of characters that are escaped depends on the setting of the
10842 * boolean argument $escape-reserved.
10843 *
10844 * If $escape-reserved is true, all characters are escaped other than lower
10845 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
10846 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
10847 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
10848 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
10849 * A-F).
10850 *
10851 * If $escape-reserved is false, the behavior differs in that characters
10852 * referred to in [RFC 2396] as reserved characters are not escaped. These
10853 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
10854 *
10855 * [RFC 2396] does not define whether escaped URIs should use lower case or
10856 * upper case for hexadecimal digits. To ensure that escaped URIs can be
10857 * compared using string comparison functions, this function must always use
10858 * the upper-case letters A-F.
10859 *
10860 * Generally, $escape-reserved should be set to true when escaping a string
10861 * that is to form a single part of a URI, and to false when escaping an
10862 * entire URI or URI reference.
10863 *
10864 * In the case of non-ascii characters, the string is encoded according to
10865 * utf-8 and then converted according to RFC 2396.
10866 *
10867 * Examples
10868 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
10869 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
10870 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
10871 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
10872 *
10873 */
Daniel Veillard118aed72002-09-24 14:13:13 +000010874static void
Daniel Veillard42766c02002-08-22 20:52:17 +000010875xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
10876 xmlXPathObjectPtr str;
10877 int escape_reserved;
10878 xmlBufferPtr target;
10879 xmlChar *cptr;
10880 xmlChar escape[4];
10881
10882 CHECK_ARITY(2);
10883
10884 escape_reserved = xmlXPathPopBoolean(ctxt);
10885
10886 CAST_TO_STRING;
10887 str = valuePop(ctxt);
10888
10889 target = xmlBufferCreate();
10890
10891 escape[0] = '%';
10892 escape[3] = 0;
10893
10894 if (target) {
10895 for (cptr = str->stringval; *cptr; cptr++) {
10896 if ((*cptr >= 'A' && *cptr <= 'Z') ||
10897 (*cptr >= 'a' && *cptr <= 'z') ||
10898 (*cptr >= '0' && *cptr <= '9') ||
10899 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
10900 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
10901 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
10902 (*cptr == '%' &&
10903 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
10904 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
10905 (cptr[1] >= '0' && cptr[1] <= '9')) &&
10906 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
10907 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
10908 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
10909 (!escape_reserved &&
10910 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
10911 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
10912 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
10913 *cptr == ','))) {
10914 xmlBufferAdd(target, cptr, 1);
10915 } else {
10916 if ((*cptr >> 4) < 10)
10917 escape[1] = '0' + (*cptr >> 4);
10918 else
10919 escape[1] = 'A' - 10 + (*cptr >> 4);
10920 if ((*cptr & 0xF) < 10)
10921 escape[2] = '0' + (*cptr & 0xF);
10922 else
10923 escape[2] = 'A' - 10 + (*cptr & 0xF);
10924
10925 xmlBufferAdd(target, &escape[0], 3);
10926 }
10927 }
10928 }
10929 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
10930 xmlBufferFree(target);
10931 xmlXPathFreeObject(str);
10932}
10933
Owen Taylor3473f882001-02-23 17:55:21 +000010934/**
10935 * xmlXPathRegisterAllFunctions:
10936 * @ctxt: the XPath context
10937 *
10938 * Registers all default XPath functions in this context
10939 */
10940void
10941xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
10942{
10943 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
10944 xmlXPathBooleanFunction);
10945 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
10946 xmlXPathCeilingFunction);
10947 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
10948 xmlXPathCountFunction);
10949 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
10950 xmlXPathConcatFunction);
10951 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
10952 xmlXPathContainsFunction);
10953 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
10954 xmlXPathIdFunction);
10955 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
10956 xmlXPathFalseFunction);
10957 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
10958 xmlXPathFloorFunction);
10959 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
10960 xmlXPathLastFunction);
10961 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
10962 xmlXPathLangFunction);
10963 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
10964 xmlXPathLocalNameFunction);
10965 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
10966 xmlXPathNotFunction);
10967 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
10968 xmlXPathNameFunction);
10969 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
10970 xmlXPathNamespaceURIFunction);
10971 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
10972 xmlXPathNormalizeFunction);
10973 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
10974 xmlXPathNumberFunction);
10975 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
10976 xmlXPathPositionFunction);
10977 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
10978 xmlXPathRoundFunction);
10979 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
10980 xmlXPathStringFunction);
10981 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
10982 xmlXPathStringLengthFunction);
10983 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
10984 xmlXPathStartsWithFunction);
10985 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
10986 xmlXPathSubstringFunction);
10987 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
10988 xmlXPathSubstringBeforeFunction);
10989 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
10990 xmlXPathSubstringAfterFunction);
10991 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
10992 xmlXPathSumFunction);
10993 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
10994 xmlXPathTrueFunction);
10995 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
10996 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000010997
10998 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
10999 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
11000 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000011001}
11002
11003#endif /* LIBXML_XPATH_ENABLED */