blob: 86163f1b4329555baf05e2faec73e6058ccd73db [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;
Daniel Veillard71f9d732003-01-14 16:07:16 +00007620 if (CUR != ')') {
7621 while (CUR != 0) {
7622 int op1 = ctxt->comp->last;
7623 ctxt->comp->last = -1;
7624 xmlXPathCompileExpr(ctxt);
7625 CHECK_ERROR;
7626 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
7627 nbargs++;
7628 if (CUR == ')') break;
7629 if (CUR != ',') {
7630 XP_ERROR(XPATH_EXPR_ERROR);
7631 }
7632 NEXT;
7633 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007634 }
Owen Taylor3473f882001-02-23 17:55:21 +00007635 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007636 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7637 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007638 NEXT;
7639 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007640}
7641
7642/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007643 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007644 * @ctxt: the XPath Parser context
7645 *
7646 * [15] PrimaryExpr ::= VariableReference
7647 * | '(' Expr ')'
7648 * | Literal
7649 * | Number
7650 * | FunctionCall
7651 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007652 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007653 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007654static void
7655xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007656 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007657 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007658 else if (CUR == '(') {
7659 NEXT;
7660 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007661 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007662 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00007663 if (CUR != ')') {
7664 XP_ERROR(XPATH_EXPR_ERROR);
7665 }
7666 NEXT;
7667 SKIP_BLANKS;
Daniel Veillard01917aa2002-04-10 11:30:41 +00007668 } else if (IS_DIGIT(CUR) || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007669 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007670 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007671 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007672 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007673 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007674 }
7675 SKIP_BLANKS;
7676}
7677
7678/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007679 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007680 * @ctxt: the XPath Parser context
7681 *
7682 * [20] FilterExpr ::= PrimaryExpr
7683 * | FilterExpr Predicate
7684 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007685 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007686 * Square brackets are used to filter expressions in the same way that
7687 * they are used in location paths. It is an error if the expression to
7688 * be filtered does not evaluate to a node-set. The context node list
7689 * used for evaluating the expression in square brackets is the node-set
7690 * to be filtered listed in document order.
7691 */
7692
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007693static void
7694xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
7695 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007696 CHECK_ERROR;
7697 SKIP_BLANKS;
7698
7699 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007700 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00007701 SKIP_BLANKS;
7702 }
7703
7704
7705}
7706
7707/**
7708 * xmlXPathScanName:
7709 * @ctxt: the XPath Parser context
7710 *
7711 * Trickery: parse an XML name but without consuming the input flow
7712 * Needed to avoid insanity in the parser state.
7713 *
7714 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7715 * CombiningChar | Extender
7716 *
7717 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7718 *
7719 * [6] Names ::= Name (S Name)*
7720 *
7721 * Returns the Name parsed or NULL
7722 */
7723
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007724static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007725xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7726 xmlChar buf[XML_MAX_NAMELEN];
7727 int len = 0;
7728
7729 SKIP_BLANKS;
7730 if (!IS_LETTER(CUR) && (CUR != '_') &&
7731 (CUR != ':')) {
7732 return(NULL);
7733 }
7734
7735 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7736 (NXT(len) == '.') || (NXT(len) == '-') ||
7737 (NXT(len) == '_') || (NXT(len) == ':') ||
7738 (IS_COMBINING(NXT(len))) ||
7739 (IS_EXTENDER(NXT(len)))) {
7740 buf[len] = NXT(len);
7741 len++;
7742 if (len >= XML_MAX_NAMELEN) {
7743 xmlGenericError(xmlGenericErrorContext,
7744 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
7745 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7746 (NXT(len) == '.') || (NXT(len) == '-') ||
7747 (NXT(len) == '_') || (NXT(len) == ':') ||
7748 (IS_COMBINING(NXT(len))) ||
7749 (IS_EXTENDER(NXT(len))))
7750 len++;
7751 break;
7752 }
7753 }
7754 return(xmlStrndup(buf, len));
7755}
7756
7757/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007758 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007759 * @ctxt: the XPath Parser context
7760 *
7761 * [19] PathExpr ::= LocationPath
7762 * | FilterExpr
7763 * | FilterExpr '/' RelativeLocationPath
7764 * | FilterExpr '//' RelativeLocationPath
7765 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007766 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007767 * The / operator and // operators combine an arbitrary expression
7768 * and a relative location path. It is an error if the expression
7769 * does not evaluate to a node-set.
7770 * The / operator does composition in the same way as when / is
7771 * used in a location path. As in location paths, // is short for
7772 * /descendant-or-self::node()/.
7773 */
7774
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007775static void
7776xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007777 int lc = 1; /* Should we branch to LocationPath ? */
7778 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7779
7780 SKIP_BLANKS;
7781 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
Daniel Veillard01917aa2002-04-10 11:30:41 +00007782 (CUR == '\'') || (CUR == '"') || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00007783 lc = 0;
7784 } else if (CUR == '*') {
7785 /* relative or absolute location path */
7786 lc = 1;
7787 } else if (CUR == '/') {
7788 /* relative or absolute location path */
7789 lc = 1;
7790 } else if (CUR == '@') {
7791 /* relative abbreviated attribute location path */
7792 lc = 1;
7793 } else if (CUR == '.') {
7794 /* relative abbreviated attribute location path */
7795 lc = 1;
7796 } else {
7797 /*
7798 * Problem is finding if we have a name here whether it's:
7799 * - a nodetype
7800 * - a function call in which case it's followed by '('
7801 * - an axis in which case it's followed by ':'
7802 * - a element name
7803 * We do an a priori analysis here rather than having to
7804 * maintain parsed token content through the recursive function
7805 * calls. This looks uglier but makes the code quite easier to
7806 * read/write/debug.
7807 */
7808 SKIP_BLANKS;
7809 name = xmlXPathScanName(ctxt);
7810 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7811#ifdef DEBUG_STEP
7812 xmlGenericError(xmlGenericErrorContext,
7813 "PathExpr: Axis\n");
7814#endif
7815 lc = 1;
7816 xmlFree(name);
7817 } else if (name != NULL) {
7818 int len =xmlStrlen(name);
7819 int blank = 0;
7820
7821
7822 while (NXT(len) != 0) {
7823 if (NXT(len) == '/') {
7824 /* element name */
7825#ifdef DEBUG_STEP
7826 xmlGenericError(xmlGenericErrorContext,
7827 "PathExpr: AbbrRelLocation\n");
7828#endif
7829 lc = 1;
7830 break;
7831 } else if (IS_BLANK(NXT(len))) {
7832 /* skip to next */
7833 blank = 1;
7834 } else if (NXT(len) == ':') {
7835#ifdef DEBUG_STEP
7836 xmlGenericError(xmlGenericErrorContext,
7837 "PathExpr: AbbrRelLocation\n");
7838#endif
7839 lc = 1;
7840 break;
7841 } else if ((NXT(len) == '(')) {
7842 /* Note Type or Function */
7843 if (xmlXPathIsNodeType(name)) {
7844#ifdef DEBUG_STEP
7845 xmlGenericError(xmlGenericErrorContext,
7846 "PathExpr: Type search\n");
7847#endif
7848 lc = 1;
7849 } else {
7850#ifdef DEBUG_STEP
7851 xmlGenericError(xmlGenericErrorContext,
7852 "PathExpr: function call\n");
7853#endif
7854 lc = 0;
7855 }
7856 break;
7857 } else if ((NXT(len) == '[')) {
7858 /* element name */
7859#ifdef DEBUG_STEP
7860 xmlGenericError(xmlGenericErrorContext,
7861 "PathExpr: AbbrRelLocation\n");
7862#endif
7863 lc = 1;
7864 break;
7865 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
7866 (NXT(len) == '=')) {
7867 lc = 1;
7868 break;
7869 } else {
7870 lc = 1;
7871 break;
7872 }
7873 len++;
7874 }
7875 if (NXT(len) == 0) {
7876#ifdef DEBUG_STEP
7877 xmlGenericError(xmlGenericErrorContext,
7878 "PathExpr: AbbrRelLocation\n");
7879#endif
7880 /* element name */
7881 lc = 1;
7882 }
7883 xmlFree(name);
7884 } else {
7885 /* make sure all cases are covered explicitely */
7886 XP_ERROR(XPATH_EXPR_ERROR);
7887 }
7888 }
7889
7890 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007891 if (CUR == '/') {
7892 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
7893 } else {
7894 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007895 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007896 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007897 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007898 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007899 CHECK_ERROR;
7900 if ((CUR == '/') && (NXT(1) == '/')) {
7901 SKIP(2);
7902 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007903
7904 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7905 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
7906 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
7907
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007908 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007909 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007910 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007911 }
7912 }
7913 SKIP_BLANKS;
7914}
7915
7916/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007917 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007918 * @ctxt: the XPath Parser context
7919 *
7920 * [18] UnionExpr ::= PathExpr
7921 * | UnionExpr '|' PathExpr
7922 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007923 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007924 */
7925
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007926static void
7927xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
7928 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007929 CHECK_ERROR;
7930 SKIP_BLANKS;
7931 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007932 int op1 = ctxt->comp->last;
7933 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007934
7935 NEXT;
7936 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007937 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007938
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007939 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
7940
Owen Taylor3473f882001-02-23 17:55:21 +00007941 SKIP_BLANKS;
7942 }
Owen Taylor3473f882001-02-23 17:55:21 +00007943}
7944
7945/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007946 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007947 * @ctxt: the XPath Parser context
7948 *
7949 * [27] UnaryExpr ::= UnionExpr
7950 * | '-' UnaryExpr
7951 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007952 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007953 */
7954
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007955static void
7956xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007957 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007958 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007959
7960 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00007961 while (CUR == '-') {
7962 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007963 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007964 NEXT;
7965 SKIP_BLANKS;
7966 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007967
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007968 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007969 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007970 if (found) {
7971 if (minus)
7972 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
7973 else
7974 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007975 }
7976}
7977
7978/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007979 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007980 * @ctxt: the XPath Parser context
7981 *
7982 * [26] MultiplicativeExpr ::= UnaryExpr
7983 * | MultiplicativeExpr MultiplyOperator UnaryExpr
7984 * | MultiplicativeExpr 'div' UnaryExpr
7985 * | MultiplicativeExpr 'mod' UnaryExpr
7986 * [34] MultiplyOperator ::= '*'
7987 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007988 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007989 */
7990
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007991static void
7992xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
7993 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007994 CHECK_ERROR;
7995 SKIP_BLANKS;
7996 while ((CUR == '*') ||
7997 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
7998 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
7999 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008000 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008001
8002 if (CUR == '*') {
8003 op = 0;
8004 NEXT;
8005 } else if (CUR == 'd') {
8006 op = 1;
8007 SKIP(3);
8008 } else if (CUR == 'm') {
8009 op = 2;
8010 SKIP(3);
8011 }
8012 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008013 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008014 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008015 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008016 SKIP_BLANKS;
8017 }
8018}
8019
8020/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008021 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008022 * @ctxt: the XPath Parser context
8023 *
8024 * [25] AdditiveExpr ::= MultiplicativeExpr
8025 * | AdditiveExpr '+' MultiplicativeExpr
8026 * | AdditiveExpr '-' MultiplicativeExpr
8027 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008028 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008029 */
8030
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008031static void
8032xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008033
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008034 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008035 CHECK_ERROR;
8036 SKIP_BLANKS;
8037 while ((CUR == '+') || (CUR == '-')) {
8038 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008039 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008040
8041 if (CUR == '+') plus = 1;
8042 else plus = 0;
8043 NEXT;
8044 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008045 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008046 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008047 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008048 SKIP_BLANKS;
8049 }
8050}
8051
8052/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008053 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008054 * @ctxt: the XPath Parser context
8055 *
8056 * [24] RelationalExpr ::= AdditiveExpr
8057 * | RelationalExpr '<' AdditiveExpr
8058 * | RelationalExpr '>' AdditiveExpr
8059 * | RelationalExpr '<=' AdditiveExpr
8060 * | RelationalExpr '>=' AdditiveExpr
8061 *
8062 * A <= B > C is allowed ? Answer from James, yes with
8063 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8064 * which is basically what got implemented.
8065 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008066 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00008067 * on the stack
8068 */
8069
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008070static void
8071xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8072 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008073 CHECK_ERROR;
8074 SKIP_BLANKS;
8075 while ((CUR == '<') ||
8076 (CUR == '>') ||
8077 ((CUR == '<') && (NXT(1) == '=')) ||
8078 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008079 int inf, strict;
8080 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008081
8082 if (CUR == '<') inf = 1;
8083 else inf = 0;
8084 if (NXT(1) == '=') strict = 0;
8085 else strict = 1;
8086 NEXT;
8087 if (!strict) NEXT;
8088 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008089 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008090 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008091 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00008092 SKIP_BLANKS;
8093 }
8094}
8095
8096/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008097 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008098 * @ctxt: the XPath Parser context
8099 *
8100 * [23] EqualityExpr ::= RelationalExpr
8101 * | EqualityExpr '=' RelationalExpr
8102 * | EqualityExpr '!=' RelationalExpr
8103 *
8104 * A != B != C is allowed ? Answer from James, yes with
8105 * (RelationalExpr = RelationalExpr) = RelationalExpr
8106 * (RelationalExpr != RelationalExpr) != RelationalExpr
8107 * which is basically what got implemented.
8108 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008109 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008110 *
8111 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008112static void
8113xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8114 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008115 CHECK_ERROR;
8116 SKIP_BLANKS;
8117 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008118 int eq;
8119 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008120
8121 if (CUR == '=') eq = 1;
8122 else eq = 0;
8123 NEXT;
8124 if (!eq) NEXT;
8125 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008126 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008127 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008128 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008129 SKIP_BLANKS;
8130 }
8131}
8132
8133/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008134 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008135 * @ctxt: the XPath Parser context
8136 *
8137 * [22] AndExpr ::= EqualityExpr
8138 * | AndExpr 'and' EqualityExpr
8139 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008140 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008141 *
8142 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008143static void
8144xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8145 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008146 CHECK_ERROR;
8147 SKIP_BLANKS;
8148 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008149 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008150 SKIP(3);
8151 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008152 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008153 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008154 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008155 SKIP_BLANKS;
8156 }
8157}
8158
8159/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008160 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008161 * @ctxt: the XPath Parser context
8162 *
8163 * [14] Expr ::= OrExpr
8164 * [21] OrExpr ::= AndExpr
8165 * | OrExpr 'or' AndExpr
8166 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008167 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00008168 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008169static void
8170xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8171 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008172 CHECK_ERROR;
8173 SKIP_BLANKS;
8174 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008175 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008176 SKIP(2);
8177 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008178 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008179 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008180 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8181 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00008182 SKIP_BLANKS;
8183 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008184 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8185 /* more ops could be optimized too */
8186 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8187 }
Owen Taylor3473f882001-02-23 17:55:21 +00008188}
8189
8190/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008191 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00008192 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008193 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00008194 *
8195 * [8] Predicate ::= '[' PredicateExpr ']'
8196 * [9] PredicateExpr ::= Expr
8197 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008198 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008199 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008200static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008201xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008202 int op1 = ctxt->comp->last;
8203
8204 SKIP_BLANKS;
8205 if (CUR != '[') {
8206 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8207 }
8208 NEXT;
8209 SKIP_BLANKS;
8210
8211 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008212 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008213 CHECK_ERROR;
8214
8215 if (CUR != ']') {
8216 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8217 }
8218
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008219 if (filter)
8220 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8221 else
8222 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008223
8224 NEXT;
8225 SKIP_BLANKS;
8226}
8227
8228/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008229 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00008230 * @ctxt: the XPath Parser context
8231 * @test: pointer to a xmlXPathTestVal
8232 * @type: pointer to a xmlXPathTypeVal
8233 * @prefix: placeholder for a possible name prefix
8234 *
8235 * [7] NodeTest ::= NameTest
8236 * | NodeType '(' ')'
8237 * | 'processing-instruction' '(' Literal ')'
8238 *
8239 * [37] NameTest ::= '*'
8240 * | NCName ':' '*'
8241 * | QName
8242 * [38] NodeType ::= 'comment'
8243 * | 'text'
8244 * | 'processing-instruction'
8245 * | 'node'
8246 *
8247 * Returns the name found and update @test, @type and @prefix appropriately
8248 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008249static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008250xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8251 xmlXPathTypeVal *type, const xmlChar **prefix,
8252 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008253 int blanks;
8254
8255 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8256 STRANGE;
8257 return(NULL);
8258 }
8259 *type = 0;
8260 *test = 0;
8261 *prefix = NULL;
8262 SKIP_BLANKS;
8263
8264 if ((name == NULL) && (CUR == '*')) {
8265 /*
8266 * All elements
8267 */
8268 NEXT;
8269 *test = NODE_TEST_ALL;
8270 return(NULL);
8271 }
8272
8273 if (name == NULL)
8274 name = xmlXPathParseNCName(ctxt);
8275 if (name == NULL) {
8276 XP_ERROR0(XPATH_EXPR_ERROR);
8277 }
8278
8279 blanks = IS_BLANK(CUR);
8280 SKIP_BLANKS;
8281 if (CUR == '(') {
8282 NEXT;
8283 /*
8284 * NodeType or PI search
8285 */
8286 if (xmlStrEqual(name, BAD_CAST "comment"))
8287 *type = NODE_TYPE_COMMENT;
8288 else if (xmlStrEqual(name, BAD_CAST "node"))
8289 *type = NODE_TYPE_NODE;
8290 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8291 *type = NODE_TYPE_PI;
8292 else if (xmlStrEqual(name, BAD_CAST "text"))
8293 *type = NODE_TYPE_TEXT;
8294 else {
8295 if (name != NULL)
8296 xmlFree(name);
8297 XP_ERROR0(XPATH_EXPR_ERROR);
8298 }
8299
8300 *test = NODE_TEST_TYPE;
8301
8302 SKIP_BLANKS;
8303 if (*type == NODE_TYPE_PI) {
8304 /*
8305 * Specific case: search a PI by name.
8306 */
Owen Taylor3473f882001-02-23 17:55:21 +00008307 if (name != NULL)
8308 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008309 name = NULL;
8310 if (CUR != ')') {
8311 name = xmlXPathParseLiteral(ctxt);
8312 CHECK_ERROR 0;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00008313 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00008314 SKIP_BLANKS;
8315 }
Owen Taylor3473f882001-02-23 17:55:21 +00008316 }
8317 if (CUR != ')') {
8318 if (name != NULL)
8319 xmlFree(name);
8320 XP_ERROR0(XPATH_UNCLOSED_ERROR);
8321 }
8322 NEXT;
8323 return(name);
8324 }
8325 *test = NODE_TEST_NAME;
8326 if ((!blanks) && (CUR == ':')) {
8327 NEXT;
8328
8329 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008330 * Since currently the parser context don't have a
8331 * namespace list associated:
8332 * The namespace name for this prefix can be computed
8333 * only at evaluation time. The compilation is done
8334 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008335 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008336#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008337 *prefix = xmlXPathNsLookup(ctxt->context, name);
8338 if (name != NULL)
8339 xmlFree(name);
8340 if (*prefix == NULL) {
8341 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8342 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008343#else
8344 *prefix = name;
8345#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008346
8347 if (CUR == '*') {
8348 /*
8349 * All elements
8350 */
8351 NEXT;
8352 *test = NODE_TEST_ALL;
8353 return(NULL);
8354 }
8355
8356 name = xmlXPathParseNCName(ctxt);
8357 if (name == NULL) {
8358 XP_ERROR0(XPATH_EXPR_ERROR);
8359 }
8360 }
8361 return(name);
8362}
8363
8364/**
8365 * xmlXPathIsAxisName:
8366 * @name: a preparsed name token
8367 *
8368 * [6] AxisName ::= 'ancestor'
8369 * | 'ancestor-or-self'
8370 * | 'attribute'
8371 * | 'child'
8372 * | 'descendant'
8373 * | 'descendant-or-self'
8374 * | 'following'
8375 * | 'following-sibling'
8376 * | 'namespace'
8377 * | 'parent'
8378 * | 'preceding'
8379 * | 'preceding-sibling'
8380 * | 'self'
8381 *
8382 * Returns the axis or 0
8383 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008384static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008385xmlXPathIsAxisName(const xmlChar *name) {
8386 xmlXPathAxisVal ret = 0;
8387 switch (name[0]) {
8388 case 'a':
8389 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8390 ret = AXIS_ANCESTOR;
8391 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8392 ret = AXIS_ANCESTOR_OR_SELF;
8393 if (xmlStrEqual(name, BAD_CAST "attribute"))
8394 ret = AXIS_ATTRIBUTE;
8395 break;
8396 case 'c':
8397 if (xmlStrEqual(name, BAD_CAST "child"))
8398 ret = AXIS_CHILD;
8399 break;
8400 case 'd':
8401 if (xmlStrEqual(name, BAD_CAST "descendant"))
8402 ret = AXIS_DESCENDANT;
8403 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8404 ret = AXIS_DESCENDANT_OR_SELF;
8405 break;
8406 case 'f':
8407 if (xmlStrEqual(name, BAD_CAST "following"))
8408 ret = AXIS_FOLLOWING;
8409 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8410 ret = AXIS_FOLLOWING_SIBLING;
8411 break;
8412 case 'n':
8413 if (xmlStrEqual(name, BAD_CAST "namespace"))
8414 ret = AXIS_NAMESPACE;
8415 break;
8416 case 'p':
8417 if (xmlStrEqual(name, BAD_CAST "parent"))
8418 ret = AXIS_PARENT;
8419 if (xmlStrEqual(name, BAD_CAST "preceding"))
8420 ret = AXIS_PRECEDING;
8421 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8422 ret = AXIS_PRECEDING_SIBLING;
8423 break;
8424 case 's':
8425 if (xmlStrEqual(name, BAD_CAST "self"))
8426 ret = AXIS_SELF;
8427 break;
8428 }
8429 return(ret);
8430}
8431
8432/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008433 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008434 * @ctxt: the XPath Parser context
8435 *
8436 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8437 * | AbbreviatedStep
8438 *
8439 * [12] AbbreviatedStep ::= '.' | '..'
8440 *
8441 * [5] AxisSpecifier ::= AxisName '::'
8442 * | AbbreviatedAxisSpecifier
8443 *
8444 * [13] AbbreviatedAxisSpecifier ::= '@'?
8445 *
8446 * Modified for XPtr range support as:
8447 *
8448 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8449 * | AbbreviatedStep
8450 * | 'range-to' '(' Expr ')' Predicate*
8451 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008452 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008453 * A location step of . is short for self::node(). This is
8454 * particularly useful in conjunction with //. For example, the
8455 * location path .//para is short for
8456 * self::node()/descendant-or-self::node()/child::para
8457 * and so will select all para descendant elements of the context
8458 * node.
8459 * Similarly, a location step of .. is short for parent::node().
8460 * For example, ../title is short for parent::node()/child::title
8461 * and so will select the title children of the parent of the context
8462 * node.
8463 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008464static void
8465xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008466#ifdef LIBXML_XPTR_ENABLED
8467 int rangeto = 0;
8468 int op2 = -1;
8469#endif
8470
Owen Taylor3473f882001-02-23 17:55:21 +00008471 SKIP_BLANKS;
8472 if ((CUR == '.') && (NXT(1) == '.')) {
8473 SKIP(2);
8474 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008475 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8476 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008477 } else if (CUR == '.') {
8478 NEXT;
8479 SKIP_BLANKS;
8480 } else {
8481 xmlChar *name = NULL;
8482 const xmlChar *prefix = NULL;
8483 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008484 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008485 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008486 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008487
8488 /*
8489 * The modification needed for XPointer change to the production
8490 */
8491#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008492 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008493 name = xmlXPathParseNCName(ctxt);
8494 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008495 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008496 xmlFree(name);
8497 SKIP_BLANKS;
8498 if (CUR != '(') {
8499 XP_ERROR(XPATH_EXPR_ERROR);
8500 }
8501 NEXT;
8502 SKIP_BLANKS;
8503
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008504 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008505 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008506 CHECK_ERROR;
8507
8508 SKIP_BLANKS;
8509 if (CUR != ')') {
8510 XP_ERROR(XPATH_EXPR_ERROR);
8511 }
8512 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008513 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008514 goto eval_predicates;
8515 }
8516 }
8517#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008518 if (CUR == '*') {
8519 axis = AXIS_CHILD;
8520 } else {
8521 if (name == NULL)
8522 name = xmlXPathParseNCName(ctxt);
8523 if (name != NULL) {
8524 axis = xmlXPathIsAxisName(name);
8525 if (axis != 0) {
8526 SKIP_BLANKS;
8527 if ((CUR == ':') && (NXT(1) == ':')) {
8528 SKIP(2);
8529 xmlFree(name);
8530 name = NULL;
8531 } else {
8532 /* an element name can conflict with an axis one :-\ */
8533 axis = AXIS_CHILD;
8534 }
Owen Taylor3473f882001-02-23 17:55:21 +00008535 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008536 axis = AXIS_CHILD;
8537 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008538 } else if (CUR == '@') {
8539 NEXT;
8540 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008541 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008542 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008543 }
Owen Taylor3473f882001-02-23 17:55:21 +00008544 }
8545
8546 CHECK_ERROR;
8547
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008548 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008549 if (test == 0)
8550 return;
8551
8552#ifdef DEBUG_STEP
8553 xmlGenericError(xmlGenericErrorContext,
8554 "Basis : computing new set\n");
8555#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008556
Owen Taylor3473f882001-02-23 17:55:21 +00008557#ifdef DEBUG_STEP
8558 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008559 if (ctxt->value == NULL)
8560 xmlGenericError(xmlGenericErrorContext, "no value\n");
8561 else if (ctxt->value->nodesetval == NULL)
8562 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8563 else
8564 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008565#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008566
8567eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008568 op1 = ctxt->comp->last;
8569 ctxt->comp->last = -1;
8570
Owen Taylor3473f882001-02-23 17:55:21 +00008571 SKIP_BLANKS;
8572 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008573 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008574 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008575
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008576#ifdef LIBXML_XPTR_ENABLED
8577 if (rangeto) {
8578 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8579 } else
8580#endif
8581 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8582 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008583
Owen Taylor3473f882001-02-23 17:55:21 +00008584 }
8585#ifdef DEBUG_STEP
8586 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008587 if (ctxt->value == NULL)
8588 xmlGenericError(xmlGenericErrorContext, "no value\n");
8589 else if (ctxt->value->nodesetval == NULL)
8590 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8591 else
8592 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8593 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008594#endif
8595}
8596
8597/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008598 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008599 * @ctxt: the XPath Parser context
8600 *
8601 * [3] RelativeLocationPath ::= Step
8602 * | RelativeLocationPath '/' Step
8603 * | AbbreviatedRelativeLocationPath
8604 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8605 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008606 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008607 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008608static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008609xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008610(xmlXPathParserContextPtr ctxt) {
8611 SKIP_BLANKS;
8612 if ((CUR == '/') && (NXT(1) == '/')) {
8613 SKIP(2);
8614 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008615 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8616 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008617 } else if (CUR == '/') {
8618 NEXT;
8619 SKIP_BLANKS;
8620 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008621 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008622 SKIP_BLANKS;
8623 while (CUR == '/') {
8624 if ((CUR == '/') && (NXT(1) == '/')) {
8625 SKIP(2);
8626 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008627 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008628 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008629 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008630 } else if (CUR == '/') {
8631 NEXT;
8632 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008633 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008634 }
8635 SKIP_BLANKS;
8636 }
8637}
8638
8639/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008640 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008641 * @ctxt: the XPath Parser context
8642 *
8643 * [1] LocationPath ::= RelativeLocationPath
8644 * | AbsoluteLocationPath
8645 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8646 * | AbbreviatedAbsoluteLocationPath
8647 * [10] AbbreviatedAbsoluteLocationPath ::=
8648 * '//' RelativeLocationPath
8649 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008650 * Compile a location path
8651 *
Owen Taylor3473f882001-02-23 17:55:21 +00008652 * // is short for /descendant-or-self::node()/. For example,
8653 * //para is short for /descendant-or-self::node()/child::para and
8654 * so will select any para element in the document (even a para element
8655 * that is a document element will be selected by //para since the
8656 * document element node is a child of the root node); div//para is
8657 * short for div/descendant-or-self::node()/child::para and so will
8658 * select all para descendants of div children.
8659 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008660static void
8661xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008662 SKIP_BLANKS;
8663 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008664 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008665 } else {
8666 while (CUR == '/') {
8667 if ((CUR == '/') && (NXT(1) == '/')) {
8668 SKIP(2);
8669 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008670 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8671 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008672 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008673 } else if (CUR == '/') {
8674 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008675 SKIP_BLANKS;
8676 if ((CUR != 0 ) &&
8677 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
8678 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008679 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008680 }
8681 }
8682 }
8683}
8684
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008685/************************************************************************
8686 * *
8687 * XPath precompiled expression evaluation *
8688 * *
8689 ************************************************************************/
8690
Daniel Veillardf06307e2001-07-03 10:35:50 +00008691static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008692xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8693
8694/**
8695 * xmlXPathNodeCollectAndTest:
8696 * @ctxt: the XPath Parser context
8697 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008698 * @first: pointer to the first element in document order
8699 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008700 *
8701 * This is the function implementing a step: based on the current list
8702 * of nodes, it builds up a new list, looking at all nodes under that
8703 * axis and selecting them it also do the predicate filtering
8704 *
8705 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00008706 *
8707 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008708 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008709static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008710xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008711 xmlXPathStepOpPtr op,
8712 xmlNodePtr * first, xmlNodePtr * last)
8713{
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008714 xmlXPathAxisVal axis = op->value;
8715 xmlXPathTestVal test = op->value2;
8716 xmlXPathTypeVal type = op->value3;
8717 const xmlChar *prefix = op->value4;
8718 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008719 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008720
8721#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008722 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008723#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008724 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008725 xmlNodeSetPtr ret, list;
8726 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008727 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00008728 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008729 xmlNodePtr cur = NULL;
8730 xmlXPathObjectPtr obj;
8731 xmlNodeSetPtr nodelist;
8732 xmlNodePtr tmp;
8733
Daniel Veillardf06307e2001-07-03 10:35:50 +00008734 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008735 obj = valuePop(ctxt);
8736 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00008737 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008738 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008739 URI = xmlXPathNsLookup(ctxt->context, prefix);
8740 if (URI == NULL)
8741 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008742 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008743#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008744 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008745#endif
8746 switch (axis) {
8747 case AXIS_ANCESTOR:
8748#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008749 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008750#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008751 first = NULL;
8752 next = xmlXPathNextAncestor;
8753 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008754 case AXIS_ANCESTOR_OR_SELF:
8755#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008756 xmlGenericError(xmlGenericErrorContext,
8757 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008758#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008759 first = NULL;
8760 next = xmlXPathNextAncestorOrSelf;
8761 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008762 case AXIS_ATTRIBUTE:
8763#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008764 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008765#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008766 first = NULL;
8767 last = NULL;
8768 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00008769 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008770 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008771 case AXIS_CHILD:
8772#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008773 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008774#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008775 last = NULL;
8776 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00008777 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008778 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008779 case AXIS_DESCENDANT:
8780#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008781 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008782#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008783 last = NULL;
8784 next = xmlXPathNextDescendant;
8785 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008786 case AXIS_DESCENDANT_OR_SELF:
8787#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008788 xmlGenericError(xmlGenericErrorContext,
8789 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008790#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008791 last = NULL;
8792 next = xmlXPathNextDescendantOrSelf;
8793 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008794 case AXIS_FOLLOWING:
8795#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008796 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008797#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008798 last = NULL;
8799 next = xmlXPathNextFollowing;
8800 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008801 case AXIS_FOLLOWING_SIBLING:
8802#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008803 xmlGenericError(xmlGenericErrorContext,
8804 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008805#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008806 last = NULL;
8807 next = xmlXPathNextFollowingSibling;
8808 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008809 case AXIS_NAMESPACE:
8810#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008811 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008812#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008813 first = NULL;
8814 last = NULL;
8815 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00008816 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008817 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008818 case AXIS_PARENT:
8819#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008820 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008821#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008822 first = NULL;
8823 next = xmlXPathNextParent;
8824 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008825 case AXIS_PRECEDING:
8826#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008827 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008828#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008829 first = NULL;
8830 next = xmlXPathNextPrecedingInternal;
8831 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008832 case AXIS_PRECEDING_SIBLING:
8833#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008834 xmlGenericError(xmlGenericErrorContext,
8835 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008836#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008837 first = NULL;
8838 next = xmlXPathNextPrecedingSibling;
8839 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008840 case AXIS_SELF:
8841#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008842 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008843#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008844 first = NULL;
8845 last = NULL;
8846 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00008847 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008848 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008849 }
8850 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008851 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008852
8853 nodelist = obj->nodesetval;
8854 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008855 xmlXPathFreeObject(obj);
8856 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8857 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008858 }
8859 addNode = xmlXPathNodeSetAddUnique;
8860 ret = NULL;
8861#ifdef DEBUG_STEP
8862 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008863 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008864 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008865 case NODE_TEST_NONE:
8866 xmlGenericError(xmlGenericErrorContext,
8867 " searching for none !!!\n");
8868 break;
8869 case NODE_TEST_TYPE:
8870 xmlGenericError(xmlGenericErrorContext,
8871 " searching for type %d\n", type);
8872 break;
8873 case NODE_TEST_PI:
8874 xmlGenericError(xmlGenericErrorContext,
8875 " searching for PI !!!\n");
8876 break;
8877 case NODE_TEST_ALL:
8878 xmlGenericError(xmlGenericErrorContext,
8879 " searching for *\n");
8880 break;
8881 case NODE_TEST_NS:
8882 xmlGenericError(xmlGenericErrorContext,
8883 " searching for namespace %s\n",
8884 prefix);
8885 break;
8886 case NODE_TEST_NAME:
8887 xmlGenericError(xmlGenericErrorContext,
8888 " searching for name %s\n", name);
8889 if (prefix != NULL)
8890 xmlGenericError(xmlGenericErrorContext,
8891 " with namespace %s\n", prefix);
8892 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008893 }
8894 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8895#endif
8896 /*
8897 * 2.3 Node Tests
8898 * - For the attribute axis, the principal node type is attribute.
8899 * - For the namespace axis, the principal node type is namespace.
8900 * - For other axes, the principal node type is element.
8901 *
8902 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008903 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008904 * select all element children of the context node
8905 */
8906 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008907 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008908 ctxt->context->node = nodelist->nodeTab[i];
8909
Daniel Veillardf06307e2001-07-03 10:35:50 +00008910 cur = NULL;
8911 list = xmlXPathNodeSetCreate(NULL);
8912 do {
8913 cur = next(ctxt, cur);
8914 if (cur == NULL)
8915 break;
8916 if ((first != NULL) && (*first == cur))
8917 break;
8918 if (((t % 256) == 0) &&
8919 (first != NULL) && (*first != NULL) &&
8920 (xmlXPathCmpNodes(*first, cur) >= 0))
8921 break;
8922 if ((last != NULL) && (*last == cur))
8923 break;
8924 if (((t % 256) == 0) &&
8925 (last != NULL) && (*last != NULL) &&
8926 (xmlXPathCmpNodes(cur, *last) >= 0))
8927 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008928 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008929#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008930 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
8931#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008932 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008933 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008934 ctxt->context->node = tmp;
8935 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008936 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008937 if ((cur->type == type) ||
8938 ((type == NODE_TYPE_NODE) &&
8939 ((cur->type == XML_DOCUMENT_NODE) ||
8940 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8941 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00008942 (cur->type == XML_NAMESPACE_DECL) ||
8943 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00008944 (cur->type == XML_PI_NODE) ||
8945 (cur->type == XML_COMMENT_NODE) ||
8946 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00008947 (cur->type == XML_TEXT_NODE))) ||
8948 ((type == NODE_TYPE_TEXT) &&
8949 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008950#ifdef DEBUG_STEP
8951 n++;
8952#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008953 addNode(list, cur);
8954 }
8955 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008956 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008957 if (cur->type == XML_PI_NODE) {
8958 if ((name != NULL) &&
8959 (!xmlStrEqual(name, cur->name)))
8960 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008961#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008962 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008963#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008964 addNode(list, cur);
8965 }
8966 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008967 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008968 if (axis == AXIS_ATTRIBUTE) {
8969 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008970#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008971 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008972#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008973 addNode(list, cur);
8974 }
8975 } else if (axis == AXIS_NAMESPACE) {
8976 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008977#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008978 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008979#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008980 xmlXPathNodeSetAddNs(list, ctxt->context->node,
8981 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008982 }
8983 } else {
8984 if (cur->type == XML_ELEMENT_NODE) {
8985 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008986#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008987 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008988#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008989 addNode(list, cur);
8990 } else if ((cur->ns != NULL) &&
8991 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008992#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008993 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008994#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008995 addNode(list, cur);
8996 }
8997 }
8998 }
8999 break;
9000 case NODE_TEST_NS:{
9001 TODO;
9002 break;
9003 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009004 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009005 switch (cur->type) {
9006 case XML_ELEMENT_NODE:
9007 if (xmlStrEqual(name, cur->name)) {
9008 if (prefix == NULL) {
9009 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009010#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009011 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009012#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009013 addNode(list, cur);
9014 }
9015 } else {
9016 if ((cur->ns != NULL) &&
9017 (xmlStrEqual(URI,
9018 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009019#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009020 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009021#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009022 addNode(list, cur);
9023 }
9024 }
9025 }
9026 break;
9027 case XML_ATTRIBUTE_NODE:{
9028 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009029
Daniel Veillardf06307e2001-07-03 10:35:50 +00009030 if (xmlStrEqual(name, attr->name)) {
9031 if (prefix == NULL) {
9032 if ((attr->ns == NULL) ||
9033 (attr->ns->prefix == NULL)) {
9034#ifdef DEBUG_STEP
9035 n++;
9036#endif
9037 addNode(list,
9038 (xmlNodePtr) attr);
9039 }
9040 } else {
9041 if ((attr->ns != NULL) &&
9042 (xmlStrEqual(URI,
9043 attr->ns->
9044 href))) {
9045#ifdef DEBUG_STEP
9046 n++;
9047#endif
9048 addNode(list,
9049 (xmlNodePtr) attr);
9050 }
9051 }
9052 }
9053 break;
9054 }
9055 case XML_NAMESPACE_DECL:
9056 if (cur->type == XML_NAMESPACE_DECL) {
9057 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009058
Daniel Veillardf06307e2001-07-03 10:35:50 +00009059 if ((ns->prefix != NULL) && (name != NULL)
9060 && (xmlStrEqual(ns->prefix, name))) {
9061#ifdef DEBUG_STEP
9062 n++;
9063#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009064 xmlXPathNodeSetAddNs(list,
9065 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009066 }
9067 }
9068 break;
9069 default:
9070 break;
9071 }
9072 break;
9073 break;
9074 }
9075 } while (cur != NULL);
9076
9077 /*
9078 * If there is some predicate filtering do it now
9079 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009080 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009081 xmlXPathObjectPtr obj2;
9082
9083 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9084 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9085 CHECK_TYPE0(XPATH_NODESET);
9086 obj2 = valuePop(ctxt);
9087 list = obj2->nodesetval;
9088 obj2->nodesetval = NULL;
9089 xmlXPathFreeObject(obj2);
9090 }
9091 if (ret == NULL) {
9092 ret = list;
9093 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009094 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009095 xmlXPathFreeNodeSet(list);
9096 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009097 }
9098 ctxt->context->node = tmp;
9099#ifdef DEBUG_STEP
9100 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009101 "\nExamined %d nodes, found %d nodes at that step\n",
9102 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009103#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009104 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009105 if ((obj->boolval) && (obj->user != NULL)) {
9106 ctxt->value->boolval = 1;
9107 ctxt->value->user = obj->user;
9108 obj->user = NULL;
9109 obj->boolval = 0;
9110 }
9111 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009112 return(t);
9113}
9114
9115/**
9116 * xmlXPathNodeCollectAndTestNth:
9117 * @ctxt: the XPath Parser context
9118 * @op: the XPath precompiled step operation
9119 * @indx: the index to collect
9120 * @first: pointer to the first element in document order
9121 * @last: pointer to the last element in document order
9122 *
9123 * This is the function implementing a step: based on the current list
9124 * of nodes, it builds up a new list, looking at all nodes under that
9125 * axis and selecting them it also do the predicate filtering
9126 *
9127 * Pushes the new NodeSet resulting from the search.
9128 * Returns the number of node traversed
9129 */
9130static int
9131xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9132 xmlXPathStepOpPtr op, int indx,
9133 xmlNodePtr * first, xmlNodePtr * last)
9134{
9135 xmlXPathAxisVal axis = op->value;
9136 xmlXPathTestVal test = op->value2;
9137 xmlXPathTypeVal type = op->value3;
9138 const xmlChar *prefix = op->value4;
9139 const xmlChar *name = op->value5;
9140 const xmlChar *URI = NULL;
9141 int n = 0, t = 0;
9142
9143 int i;
9144 xmlNodeSetPtr list;
9145 xmlXPathTraversalFunction next = NULL;
9146 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9147 xmlNodePtr cur = NULL;
9148 xmlXPathObjectPtr obj;
9149 xmlNodeSetPtr nodelist;
9150 xmlNodePtr tmp;
9151
9152 CHECK_TYPE0(XPATH_NODESET);
9153 obj = valuePop(ctxt);
9154 addNode = xmlXPathNodeSetAdd;
9155 if (prefix != NULL) {
9156 URI = xmlXPathNsLookup(ctxt->context, prefix);
9157 if (URI == NULL)
9158 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9159 }
9160#ifdef DEBUG_STEP_NTH
9161 xmlGenericError(xmlGenericErrorContext, "new step : ");
9162 if (first != NULL) {
9163 if (*first != NULL)
9164 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9165 (*first)->name);
9166 else
9167 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9168 }
9169 if (last != NULL) {
9170 if (*last != NULL)
9171 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9172 (*last)->name);
9173 else
9174 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9175 }
9176#endif
9177 switch (axis) {
9178 case AXIS_ANCESTOR:
9179#ifdef DEBUG_STEP_NTH
9180 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9181#endif
9182 first = NULL;
9183 next = xmlXPathNextAncestor;
9184 break;
9185 case AXIS_ANCESTOR_OR_SELF:
9186#ifdef DEBUG_STEP_NTH
9187 xmlGenericError(xmlGenericErrorContext,
9188 "axis 'ancestors-or-self' ");
9189#endif
9190 first = NULL;
9191 next = xmlXPathNextAncestorOrSelf;
9192 break;
9193 case AXIS_ATTRIBUTE:
9194#ifdef DEBUG_STEP_NTH
9195 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9196#endif
9197 first = NULL;
9198 last = NULL;
9199 next = xmlXPathNextAttribute;
9200 break;
9201 case AXIS_CHILD:
9202#ifdef DEBUG_STEP_NTH
9203 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9204#endif
9205 last = NULL;
9206 next = xmlXPathNextChild;
9207 break;
9208 case AXIS_DESCENDANT:
9209#ifdef DEBUG_STEP_NTH
9210 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9211#endif
9212 last = NULL;
9213 next = xmlXPathNextDescendant;
9214 break;
9215 case AXIS_DESCENDANT_OR_SELF:
9216#ifdef DEBUG_STEP_NTH
9217 xmlGenericError(xmlGenericErrorContext,
9218 "axis 'descendant-or-self' ");
9219#endif
9220 last = NULL;
9221 next = xmlXPathNextDescendantOrSelf;
9222 break;
9223 case AXIS_FOLLOWING:
9224#ifdef DEBUG_STEP_NTH
9225 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9226#endif
9227 last = NULL;
9228 next = xmlXPathNextFollowing;
9229 break;
9230 case AXIS_FOLLOWING_SIBLING:
9231#ifdef DEBUG_STEP_NTH
9232 xmlGenericError(xmlGenericErrorContext,
9233 "axis 'following-siblings' ");
9234#endif
9235 last = NULL;
9236 next = xmlXPathNextFollowingSibling;
9237 break;
9238 case AXIS_NAMESPACE:
9239#ifdef DEBUG_STEP_NTH
9240 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9241#endif
9242 last = NULL;
9243 first = NULL;
9244 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9245 break;
9246 case AXIS_PARENT:
9247#ifdef DEBUG_STEP_NTH
9248 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9249#endif
9250 first = NULL;
9251 next = xmlXPathNextParent;
9252 break;
9253 case AXIS_PRECEDING:
9254#ifdef DEBUG_STEP_NTH
9255 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9256#endif
9257 first = NULL;
9258 next = xmlXPathNextPrecedingInternal;
9259 break;
9260 case AXIS_PRECEDING_SIBLING:
9261#ifdef DEBUG_STEP_NTH
9262 xmlGenericError(xmlGenericErrorContext,
9263 "axis 'preceding-sibling' ");
9264#endif
9265 first = NULL;
9266 next = xmlXPathNextPrecedingSibling;
9267 break;
9268 case AXIS_SELF:
9269#ifdef DEBUG_STEP_NTH
9270 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9271#endif
9272 first = NULL;
9273 last = NULL;
9274 next = xmlXPathNextSelf;
9275 break;
9276 }
9277 if (next == NULL)
9278 return(0);
9279
9280 nodelist = obj->nodesetval;
9281 if (nodelist == NULL) {
9282 xmlXPathFreeObject(obj);
9283 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9284 return(0);
9285 }
9286 addNode = xmlXPathNodeSetAddUnique;
9287#ifdef DEBUG_STEP_NTH
9288 xmlGenericError(xmlGenericErrorContext,
9289 " context contains %d nodes\n", nodelist->nodeNr);
9290 switch (test) {
9291 case NODE_TEST_NONE:
9292 xmlGenericError(xmlGenericErrorContext,
9293 " searching for none !!!\n");
9294 break;
9295 case NODE_TEST_TYPE:
9296 xmlGenericError(xmlGenericErrorContext,
9297 " searching for type %d\n", type);
9298 break;
9299 case NODE_TEST_PI:
9300 xmlGenericError(xmlGenericErrorContext,
9301 " searching for PI !!!\n");
9302 break;
9303 case NODE_TEST_ALL:
9304 xmlGenericError(xmlGenericErrorContext,
9305 " searching for *\n");
9306 break;
9307 case NODE_TEST_NS:
9308 xmlGenericError(xmlGenericErrorContext,
9309 " searching for namespace %s\n",
9310 prefix);
9311 break;
9312 case NODE_TEST_NAME:
9313 xmlGenericError(xmlGenericErrorContext,
9314 " searching for name %s\n", name);
9315 if (prefix != NULL)
9316 xmlGenericError(xmlGenericErrorContext,
9317 " with namespace %s\n", prefix);
9318 break;
9319 }
9320 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9321#endif
9322 /*
9323 * 2.3 Node Tests
9324 * - For the attribute axis, the principal node type is attribute.
9325 * - For the namespace axis, the principal node type is namespace.
9326 * - For other axes, the principal node type is element.
9327 *
9328 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009329 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009330 * select all element children of the context node
9331 */
9332 tmp = ctxt->context->node;
9333 list = xmlXPathNodeSetCreate(NULL);
9334 for (i = 0; i < nodelist->nodeNr; i++) {
9335 ctxt->context->node = nodelist->nodeTab[i];
9336
9337 cur = NULL;
9338 n = 0;
9339 do {
9340 cur = next(ctxt, cur);
9341 if (cur == NULL)
9342 break;
9343 if ((first != NULL) && (*first == cur))
9344 break;
9345 if (((t % 256) == 0) &&
9346 (first != NULL) && (*first != NULL) &&
9347 (xmlXPathCmpNodes(*first, cur) >= 0))
9348 break;
9349 if ((last != NULL) && (*last == cur))
9350 break;
9351 if (((t % 256) == 0) &&
9352 (last != NULL) && (*last != NULL) &&
9353 (xmlXPathCmpNodes(cur, *last) >= 0))
9354 break;
9355 t++;
9356 switch (test) {
9357 case NODE_TEST_NONE:
9358 ctxt->context->node = tmp;
9359 STRANGE return(0);
9360 case NODE_TEST_TYPE:
9361 if ((cur->type == type) ||
9362 ((type == NODE_TYPE_NODE) &&
9363 ((cur->type == XML_DOCUMENT_NODE) ||
9364 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9365 (cur->type == XML_ELEMENT_NODE) ||
9366 (cur->type == XML_PI_NODE) ||
9367 (cur->type == XML_COMMENT_NODE) ||
9368 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +00009369 (cur->type == XML_TEXT_NODE))) ||
9370 ((type == NODE_TYPE_TEXT) &&
9371 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009372 n++;
9373 if (n == indx)
9374 addNode(list, cur);
9375 }
9376 break;
9377 case NODE_TEST_PI:
9378 if (cur->type == XML_PI_NODE) {
9379 if ((name != NULL) &&
9380 (!xmlStrEqual(name, cur->name)))
9381 break;
9382 n++;
9383 if (n == indx)
9384 addNode(list, cur);
9385 }
9386 break;
9387 case NODE_TEST_ALL:
9388 if (axis == AXIS_ATTRIBUTE) {
9389 if (cur->type == XML_ATTRIBUTE_NODE) {
9390 n++;
9391 if (n == indx)
9392 addNode(list, cur);
9393 }
9394 } else if (axis == AXIS_NAMESPACE) {
9395 if (cur->type == XML_NAMESPACE_DECL) {
9396 n++;
9397 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009398 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9399 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009400 }
9401 } else {
9402 if (cur->type == XML_ELEMENT_NODE) {
9403 if (prefix == NULL) {
9404 n++;
9405 if (n == indx)
9406 addNode(list, cur);
9407 } else if ((cur->ns != NULL) &&
9408 (xmlStrEqual(URI, cur->ns->href))) {
9409 n++;
9410 if (n == indx)
9411 addNode(list, cur);
9412 }
9413 }
9414 }
9415 break;
9416 case NODE_TEST_NS:{
9417 TODO;
9418 break;
9419 }
9420 case NODE_TEST_NAME:
9421 switch (cur->type) {
9422 case XML_ELEMENT_NODE:
9423 if (xmlStrEqual(name, cur->name)) {
9424 if (prefix == NULL) {
9425 if (cur->ns == NULL) {
9426 n++;
9427 if (n == indx)
9428 addNode(list, cur);
9429 }
9430 } else {
9431 if ((cur->ns != NULL) &&
9432 (xmlStrEqual(URI,
9433 cur->ns->href))) {
9434 n++;
9435 if (n == indx)
9436 addNode(list, cur);
9437 }
9438 }
9439 }
9440 break;
9441 case XML_ATTRIBUTE_NODE:{
9442 xmlAttrPtr attr = (xmlAttrPtr) cur;
9443
9444 if (xmlStrEqual(name, attr->name)) {
9445 if (prefix == NULL) {
9446 if ((attr->ns == NULL) ||
9447 (attr->ns->prefix == NULL)) {
9448 n++;
9449 if (n == indx)
9450 addNode(list, cur);
9451 }
9452 } else {
9453 if ((attr->ns != NULL) &&
9454 (xmlStrEqual(URI,
9455 attr->ns->
9456 href))) {
9457 n++;
9458 if (n == indx)
9459 addNode(list, cur);
9460 }
9461 }
9462 }
9463 break;
9464 }
9465 case XML_NAMESPACE_DECL:
9466 if (cur->type == XML_NAMESPACE_DECL) {
9467 xmlNsPtr ns = (xmlNsPtr) cur;
9468
9469 if ((ns->prefix != NULL) && (name != NULL)
9470 && (xmlStrEqual(ns->prefix, name))) {
9471 n++;
9472 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009473 xmlXPathNodeSetAddNs(list,
9474 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009475 }
9476 }
9477 break;
9478 default:
9479 break;
9480 }
9481 break;
9482 break;
9483 }
9484 } while (n < indx);
9485 }
9486 ctxt->context->node = tmp;
9487#ifdef DEBUG_STEP_NTH
9488 xmlGenericError(xmlGenericErrorContext,
9489 "\nExamined %d nodes, found %d nodes at that step\n",
9490 t, list->nodeNr);
9491#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009492 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009493 if ((obj->boolval) && (obj->user != NULL)) {
9494 ctxt->value->boolval = 1;
9495 ctxt->value->user = obj->user;
9496 obj->user = NULL;
9497 obj->boolval = 0;
9498 }
9499 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009500 return(t);
9501}
9502
9503/**
9504 * xmlXPathCompOpEvalFirst:
9505 * @ctxt: the XPath parser context with the compiled expression
9506 * @op: an XPath compiled operation
9507 * @first: the first elem found so far
9508 *
9509 * Evaluate the Precompiled XPath operation searching only the first
9510 * element in document order
9511 *
9512 * Returns the number of examined objects.
9513 */
9514static int
9515xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9516 xmlXPathStepOpPtr op, xmlNodePtr * first)
9517{
9518 int total = 0, cur;
9519 xmlXPathCompExprPtr comp;
9520 xmlXPathObjectPtr arg1, arg2;
9521
Daniel Veillard556c6682001-10-06 09:59:51 +00009522 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009523 comp = ctxt->comp;
9524 switch (op->op) {
9525 case XPATH_OP_END:
9526 return (0);
9527 case XPATH_OP_UNION:
9528 total =
9529 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9530 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009531 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009532 if ((ctxt->value != NULL)
9533 && (ctxt->value->type == XPATH_NODESET)
9534 && (ctxt->value->nodesetval != NULL)
9535 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9536 /*
9537 * limit tree traversing to first node in the result
9538 */
9539 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9540 *first = ctxt->value->nodesetval->nodeTab[0];
9541 }
9542 cur =
9543 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9544 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009545 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009546 CHECK_TYPE0(XPATH_NODESET);
9547 arg2 = valuePop(ctxt);
9548
9549 CHECK_TYPE0(XPATH_NODESET);
9550 arg1 = valuePop(ctxt);
9551
9552 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9553 arg2->nodesetval);
9554 valuePush(ctxt, arg1);
9555 xmlXPathFreeObject(arg2);
9556 /* optimizer */
9557 if (total > cur)
9558 xmlXPathCompSwap(op);
9559 return (total + cur);
9560 case XPATH_OP_ROOT:
9561 xmlXPathRoot(ctxt);
9562 return (0);
9563 case XPATH_OP_NODE:
9564 if (op->ch1 != -1)
9565 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009566 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009567 if (op->ch2 != -1)
9568 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009569 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009570 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9571 return (total);
9572 case XPATH_OP_RESET:
9573 if (op->ch1 != -1)
9574 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009575 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009576 if (op->ch2 != -1)
9577 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009578 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009579 ctxt->context->node = NULL;
9580 return (total);
9581 case XPATH_OP_COLLECT:{
9582 if (op->ch1 == -1)
9583 return (total);
9584
9585 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009586 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009587
9588 /*
9589 * Optimization for [n] selection where n is a number
9590 */
9591 if ((op->ch2 != -1) &&
9592 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9593 (comp->steps[op->ch2].ch1 == -1) &&
9594 (comp->steps[op->ch2].ch2 != -1) &&
9595 (comp->steps[comp->steps[op->ch2].ch2].op ==
9596 XPATH_OP_VALUE)) {
9597 xmlXPathObjectPtr val;
9598
9599 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9600 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9601 int indx = (int) val->floatval;
9602
9603 if (val->floatval == (float) indx) {
9604 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9605 first, NULL);
9606 return (total);
9607 }
9608 }
9609 }
9610 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9611 return (total);
9612 }
9613 case XPATH_OP_VALUE:
9614 valuePush(ctxt,
9615 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9616 return (0);
9617 case XPATH_OP_SORT:
9618 if (op->ch1 != -1)
9619 total +=
9620 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9621 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009622 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009623 if ((ctxt->value != NULL)
9624 && (ctxt->value->type == XPATH_NODESET)
9625 && (ctxt->value->nodesetval != NULL))
9626 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9627 return (total);
9628 default:
9629 return (xmlXPathCompOpEval(ctxt, op));
9630 }
9631}
9632
9633/**
9634 * xmlXPathCompOpEvalLast:
9635 * @ctxt: the XPath parser context with the compiled expression
9636 * @op: an XPath compiled operation
9637 * @last: the last elem found so far
9638 *
9639 * Evaluate the Precompiled XPath operation searching only the last
9640 * element in document order
9641 *
9642 * Returns the number of node traversed
9643 */
9644static int
9645xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9646 xmlNodePtr * last)
9647{
9648 int total = 0, cur;
9649 xmlXPathCompExprPtr comp;
9650 xmlXPathObjectPtr arg1, arg2;
9651
Daniel Veillard556c6682001-10-06 09:59:51 +00009652 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009653 comp = ctxt->comp;
9654 switch (op->op) {
9655 case XPATH_OP_END:
9656 return (0);
9657 case XPATH_OP_UNION:
9658 total =
9659 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009660 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009661 if ((ctxt->value != NULL)
9662 && (ctxt->value->type == XPATH_NODESET)
9663 && (ctxt->value->nodesetval != NULL)
9664 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9665 /*
9666 * limit tree traversing to first node in the result
9667 */
9668 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9669 *last =
9670 ctxt->value->nodesetval->nodeTab[ctxt->value->
9671 nodesetval->nodeNr -
9672 1];
9673 }
9674 cur =
9675 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009676 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009677 if ((ctxt->value != NULL)
9678 && (ctxt->value->type == XPATH_NODESET)
9679 && (ctxt->value->nodesetval != NULL)
9680 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9681 }
9682 CHECK_TYPE0(XPATH_NODESET);
9683 arg2 = valuePop(ctxt);
9684
9685 CHECK_TYPE0(XPATH_NODESET);
9686 arg1 = valuePop(ctxt);
9687
9688 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9689 arg2->nodesetval);
9690 valuePush(ctxt, arg1);
9691 xmlXPathFreeObject(arg2);
9692 /* optimizer */
9693 if (total > cur)
9694 xmlXPathCompSwap(op);
9695 return (total + cur);
9696 case XPATH_OP_ROOT:
9697 xmlXPathRoot(ctxt);
9698 return (0);
9699 case XPATH_OP_NODE:
9700 if (op->ch1 != -1)
9701 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009702 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009703 if (op->ch2 != -1)
9704 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009705 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009706 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9707 return (total);
9708 case XPATH_OP_RESET:
9709 if (op->ch1 != -1)
9710 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009711 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009712 if (op->ch2 != -1)
9713 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009714 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009715 ctxt->context->node = NULL;
9716 return (total);
9717 case XPATH_OP_COLLECT:{
9718 if (op->ch1 == -1)
9719 return (0);
9720
9721 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009722 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009723
9724 /*
9725 * Optimization for [n] selection where n is a number
9726 */
9727 if ((op->ch2 != -1) &&
9728 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9729 (comp->steps[op->ch2].ch1 == -1) &&
9730 (comp->steps[op->ch2].ch2 != -1) &&
9731 (comp->steps[comp->steps[op->ch2].ch2].op ==
9732 XPATH_OP_VALUE)) {
9733 xmlXPathObjectPtr val;
9734
9735 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9736 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9737 int indx = (int) val->floatval;
9738
9739 if (val->floatval == (float) indx) {
9740 total +=
9741 xmlXPathNodeCollectAndTestNth(ctxt, op,
9742 indx, NULL,
9743 last);
9744 return (total);
9745 }
9746 }
9747 }
9748 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9749 return (total);
9750 }
9751 case XPATH_OP_VALUE:
9752 valuePush(ctxt,
9753 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9754 return (0);
9755 case XPATH_OP_SORT:
9756 if (op->ch1 != -1)
9757 total +=
9758 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9759 last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009760 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009761 if ((ctxt->value != NULL)
9762 && (ctxt->value->type == XPATH_NODESET)
9763 && (ctxt->value->nodesetval != NULL))
9764 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9765 return (total);
9766 default:
9767 return (xmlXPathCompOpEval(ctxt, op));
9768 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009769}
9770
Owen Taylor3473f882001-02-23 17:55:21 +00009771/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009772 * xmlXPathCompOpEval:
9773 * @ctxt: the XPath parser context with the compiled expression
9774 * @op: an XPath compiled operation
9775 *
9776 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009777 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009778 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009779static int
9780xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9781{
9782 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009783 int equal, ret;
9784 xmlXPathCompExprPtr comp;
9785 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009786 xmlNodePtr bak;
9787 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +00009788 int pp;
William M. Brack692092b2002-06-28 15:01:24 +00009789 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009790
Daniel Veillard556c6682001-10-06 09:59:51 +00009791 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009792 comp = ctxt->comp;
9793 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009794 case XPATH_OP_END:
9795 return (0);
9796 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009797 bakd = ctxt->context->doc;
9798 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009799 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009800 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009801 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009802 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009803 xmlXPathBooleanFunction(ctxt, 1);
9804 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9805 return (total);
9806 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009807 ctxt->context->doc = bakd;
9808 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009809 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009810 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009811 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009812 if (ctxt->error) {
9813 xmlXPathFreeObject(arg2);
9814 return(0);
9815 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009816 xmlXPathBooleanFunction(ctxt, 1);
9817 arg1 = valuePop(ctxt);
9818 arg1->boolval &= arg2->boolval;
9819 valuePush(ctxt, arg1);
9820 xmlXPathFreeObject(arg2);
9821 return (total);
9822 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009823 bakd = ctxt->context->doc;
9824 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009825 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009826 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009827 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009828 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009829 xmlXPathBooleanFunction(ctxt, 1);
9830 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9831 return (total);
9832 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009833 ctxt->context->doc = bakd;
9834 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009835 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009836 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009837 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009838 if (ctxt->error) {
9839 xmlXPathFreeObject(arg2);
9840 return(0);
9841 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009842 xmlXPathBooleanFunction(ctxt, 1);
9843 arg1 = valuePop(ctxt);
9844 arg1->boolval |= arg2->boolval;
9845 valuePush(ctxt, arg1);
9846 xmlXPathFreeObject(arg2);
9847 return (total);
9848 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009849 bakd = ctxt->context->doc;
9850 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009851 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009852 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009853 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009854 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009855 ctxt->context->doc = bakd;
9856 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009857 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009858 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009859 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009860 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +00009861 if (op->value)
9862 equal = xmlXPathEqualValues(ctxt);
9863 else
9864 equal = xmlXPathNotEqualValues(ctxt);
9865 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +00009866 return (total);
9867 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009868 bakd = ctxt->context->doc;
9869 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009870 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009871 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009872 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009873 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009874 ctxt->context->doc = bakd;
9875 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009876 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009877 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009878 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009879 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009880 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
9881 valuePush(ctxt, xmlXPathNewBoolean(ret));
9882 return (total);
9883 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009884 bakd = ctxt->context->doc;
9885 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009886 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009887 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009888 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009889 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009890 if (op->ch2 != -1) {
9891 ctxt->context->doc = bakd;
9892 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009893 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009894 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009895 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009896 }
Daniel Veillard556c6682001-10-06 09:59:51 +00009897 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009898 if (op->value == 0)
9899 xmlXPathSubValues(ctxt);
9900 else if (op->value == 1)
9901 xmlXPathAddValues(ctxt);
9902 else if (op->value == 2)
9903 xmlXPathValueFlipSign(ctxt);
9904 else if (op->value == 3) {
9905 CAST_TO_NUMBER;
9906 CHECK_TYPE0(XPATH_NUMBER);
9907 }
9908 return (total);
9909 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009910 bakd = ctxt->context->doc;
9911 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009912 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009913 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009914 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009915 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009916 ctxt->context->doc = bakd;
9917 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009918 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009919 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009920 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009921 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009922 if (op->value == 0)
9923 xmlXPathMultValues(ctxt);
9924 else if (op->value == 1)
9925 xmlXPathDivValues(ctxt);
9926 else if (op->value == 2)
9927 xmlXPathModValues(ctxt);
9928 return (total);
9929 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009930 bakd = ctxt->context->doc;
9931 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009932 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009933 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009934 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009935 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009936 ctxt->context->doc = bakd;
9937 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009938 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009939 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009940 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009941 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009942 CHECK_TYPE0(XPATH_NODESET);
9943 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009944
Daniel Veillardf06307e2001-07-03 10:35:50 +00009945 CHECK_TYPE0(XPATH_NODESET);
9946 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009947
Daniel Veillardf06307e2001-07-03 10:35:50 +00009948 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9949 arg2->nodesetval);
9950 valuePush(ctxt, arg1);
9951 xmlXPathFreeObject(arg2);
9952 return (total);
9953 case XPATH_OP_ROOT:
9954 xmlXPathRoot(ctxt);
9955 return (total);
9956 case XPATH_OP_NODE:
9957 if (op->ch1 != -1)
9958 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009959 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009960 if (op->ch2 != -1)
9961 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009962 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009963 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9964 return (total);
9965 case XPATH_OP_RESET:
9966 if (op->ch1 != -1)
9967 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009968 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009969 if (op->ch2 != -1)
9970 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009971 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009972 ctxt->context->node = NULL;
9973 return (total);
9974 case XPATH_OP_COLLECT:{
9975 if (op->ch1 == -1)
9976 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009977
Daniel Veillardf06307e2001-07-03 10:35:50 +00009978 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009979 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009980
Daniel Veillardf06307e2001-07-03 10:35:50 +00009981 /*
9982 * Optimization for [n] selection where n is a number
9983 */
9984 if ((op->ch2 != -1) &&
9985 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9986 (comp->steps[op->ch2].ch1 == -1) &&
9987 (comp->steps[op->ch2].ch2 != -1) &&
9988 (comp->steps[comp->steps[op->ch2].ch2].op ==
9989 XPATH_OP_VALUE)) {
9990 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +00009991
Daniel Veillardf06307e2001-07-03 10:35:50 +00009992 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9993 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9994 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009995
Daniel Veillardf06307e2001-07-03 10:35:50 +00009996 if (val->floatval == (float) indx) {
9997 total +=
9998 xmlXPathNodeCollectAndTestNth(ctxt, op,
9999 indx, NULL,
10000 NULL);
10001 return (total);
10002 }
10003 }
10004 }
10005 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
10006 return (total);
10007 }
10008 case XPATH_OP_VALUE:
10009 valuePush(ctxt,
10010 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10011 return (total);
10012 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000010013 xmlXPathObjectPtr val;
10014
Daniel Veillardf06307e2001-07-03 10:35:50 +000010015 if (op->ch1 != -1)
10016 total +=
10017 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010018 if (op->value5 == NULL) {
10019 val = xmlXPathVariableLookup(ctxt->context, op->value4);
10020 if (val == NULL) {
10021 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10022 return(0);
10023 }
10024 valuePush(ctxt, val);
10025 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010026 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010027
Daniel Veillardf06307e2001-07-03 10:35:50 +000010028 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10029 if (URI == NULL) {
10030 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010031 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010032 op->value4, op->value5);
10033 return (total);
10034 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010035 val = xmlXPathVariableLookupNS(ctxt->context,
10036 op->value4, URI);
10037 if (val == NULL) {
10038 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10039 return(0);
10040 }
10041 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010042 }
10043 return (total);
10044 }
10045 case XPATH_OP_FUNCTION:{
10046 xmlXPathFunction func;
10047 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000010048 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010049
10050 if (op->ch1 != -1)
10051 total +=
10052 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010053 if (ctxt->valueNr < op->value) {
10054 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010055 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010056 ctxt->error = XPATH_INVALID_OPERAND;
10057 return (total);
10058 }
10059 for (i = 0; i < op->value; i++)
10060 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10061 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010062 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010063 ctxt->error = XPATH_INVALID_OPERAND;
10064 return (total);
10065 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010066 if (op->cache != NULL)
10067 func = (xmlXPathFunction) op->cache;
10068 else {
10069 const xmlChar *URI = NULL;
10070
10071 if (op->value5 == NULL)
10072 func =
10073 xmlXPathFunctionLookup(ctxt->context,
10074 op->value4);
10075 else {
10076 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10077 if (URI == NULL) {
10078 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010079 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010080 op->value4, op->value5);
10081 return (total);
10082 }
10083 func = xmlXPathFunctionLookupNS(ctxt->context,
10084 op->value4, URI);
10085 }
10086 if (func == NULL) {
10087 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010088 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010089 op->value4);
10090 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010091 }
10092 op->cache = (void *) func;
10093 op->cacheURI = (void *) URI;
10094 }
10095 oldFunc = ctxt->context->function;
10096 oldFuncURI = ctxt->context->functionURI;
10097 ctxt->context->function = op->value4;
10098 ctxt->context->functionURI = op->cacheURI;
10099 func(ctxt, op->value);
10100 ctxt->context->function = oldFunc;
10101 ctxt->context->functionURI = oldFuncURI;
10102 return (total);
10103 }
10104 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000010105 bakd = ctxt->context->doc;
10106 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010107 if (op->ch1 != -1)
10108 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010109 ctxt->context->doc = bakd;
10110 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010111 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010112 if (op->ch2 != -1)
10113 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010114 ctxt->context->doc = bakd;
10115 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010116 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010117 return (total);
10118 case XPATH_OP_PREDICATE:
10119 case XPATH_OP_FILTER:{
10120 xmlXPathObjectPtr res;
10121 xmlXPathObjectPtr obj, tmp;
10122 xmlNodeSetPtr newset = NULL;
10123 xmlNodeSetPtr oldset;
10124 xmlNodePtr oldnode;
10125 int i;
10126
10127 /*
10128 * Optimization for ()[1] selection i.e. the first elem
10129 */
10130 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10131 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10132 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10133 xmlXPathObjectPtr val;
10134
10135 val = comp->steps[op->ch2].value4;
10136 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10137 (val->floatval == 1.0)) {
10138 xmlNodePtr first = NULL;
10139
10140 total +=
10141 xmlXPathCompOpEvalFirst(ctxt,
10142 &comp->steps[op->ch1],
10143 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010144 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010145 /*
10146 * The nodeset should be in document order,
10147 * Keep only the first value
10148 */
10149 if ((ctxt->value != NULL) &&
10150 (ctxt->value->type == XPATH_NODESET) &&
10151 (ctxt->value->nodesetval != NULL) &&
10152 (ctxt->value->nodesetval->nodeNr > 1))
10153 ctxt->value->nodesetval->nodeNr = 1;
10154 return (total);
10155 }
10156 }
10157 /*
10158 * Optimization for ()[last()] selection i.e. the last elem
10159 */
10160 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10161 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10162 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10163 int f = comp->steps[op->ch2].ch1;
10164
10165 if ((f != -1) &&
10166 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10167 (comp->steps[f].value5 == NULL) &&
10168 (comp->steps[f].value == 0) &&
10169 (comp->steps[f].value4 != NULL) &&
10170 (xmlStrEqual
10171 (comp->steps[f].value4, BAD_CAST "last"))) {
10172 xmlNodePtr last = NULL;
10173
10174 total +=
10175 xmlXPathCompOpEvalLast(ctxt,
10176 &comp->steps[op->ch1],
10177 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010178 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010179 /*
10180 * The nodeset should be in document order,
10181 * Keep only the last value
10182 */
10183 if ((ctxt->value != NULL) &&
10184 (ctxt->value->type == XPATH_NODESET) &&
10185 (ctxt->value->nodesetval != NULL) &&
10186 (ctxt->value->nodesetval->nodeTab != NULL) &&
10187 (ctxt->value->nodesetval->nodeNr > 1)) {
10188 ctxt->value->nodesetval->nodeTab[0] =
10189 ctxt->value->nodesetval->nodeTab[ctxt->
10190 value->
10191 nodesetval->
10192 nodeNr -
10193 1];
10194 ctxt->value->nodesetval->nodeNr = 1;
10195 }
10196 return (total);
10197 }
10198 }
10199
10200 if (op->ch1 != -1)
10201 total +=
10202 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010203 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010204 if (op->ch2 == -1)
10205 return (total);
10206 if (ctxt->value == NULL)
10207 return (total);
10208
10209 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010210
10211#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010212 /*
10213 * Hum are we filtering the result of an XPointer expression
10214 */
10215 if (ctxt->value->type == XPATH_LOCATIONSET) {
10216 xmlLocationSetPtr newlocset = NULL;
10217 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010218
Daniel Veillardf06307e2001-07-03 10:35:50 +000010219 /*
10220 * Extract the old locset, and then evaluate the result of the
10221 * expression for all the element in the locset. use it to grow
10222 * up a new locset.
10223 */
10224 CHECK_TYPE0(XPATH_LOCATIONSET);
10225 obj = valuePop(ctxt);
10226 oldlocset = obj->user;
10227 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010228
Daniel Veillardf06307e2001-07-03 10:35:50 +000010229 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10230 ctxt->context->contextSize = 0;
10231 ctxt->context->proximityPosition = 0;
10232 if (op->ch2 != -1)
10233 total +=
10234 xmlXPathCompOpEval(ctxt,
10235 &comp->steps[op->ch2]);
10236 res = valuePop(ctxt);
10237 if (res != NULL)
10238 xmlXPathFreeObject(res);
10239 valuePush(ctxt, obj);
10240 CHECK_ERROR0;
10241 return (total);
10242 }
10243 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010244
Daniel Veillardf06307e2001-07-03 10:35:50 +000010245 for (i = 0; i < oldlocset->locNr; i++) {
10246 /*
10247 * Run the evaluation with a node list made of a
10248 * single item in the nodelocset.
10249 */
10250 ctxt->context->node = oldlocset->locTab[i]->user;
10251 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10252 valuePush(ctxt, tmp);
10253 ctxt->context->contextSize = oldlocset->locNr;
10254 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010255
Daniel Veillardf06307e2001-07-03 10:35:50 +000010256 if (op->ch2 != -1)
10257 total +=
10258 xmlXPathCompOpEval(ctxt,
10259 &comp->steps[op->ch2]);
10260 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010261
Daniel Veillardf06307e2001-07-03 10:35:50 +000010262 /*
10263 * The result of the evaluation need to be tested to
10264 * decided whether the filter succeeded or not
10265 */
10266 res = valuePop(ctxt);
10267 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10268 xmlXPtrLocationSetAdd(newlocset,
10269 xmlXPathObjectCopy
10270 (oldlocset->locTab[i]));
10271 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010272
Daniel Veillardf06307e2001-07-03 10:35:50 +000010273 /*
10274 * Cleanup
10275 */
10276 if (res != NULL)
10277 xmlXPathFreeObject(res);
10278 if (ctxt->value == tmp) {
10279 res = valuePop(ctxt);
10280 xmlXPathFreeObject(res);
10281 }
10282
10283 ctxt->context->node = NULL;
10284 }
10285
10286 /*
10287 * The result is used as the new evaluation locset.
10288 */
10289 xmlXPathFreeObject(obj);
10290 ctxt->context->node = NULL;
10291 ctxt->context->contextSize = -1;
10292 ctxt->context->proximityPosition = -1;
10293 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10294 ctxt->context->node = oldnode;
10295 return (total);
10296 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010297#endif /* LIBXML_XPTR_ENABLED */
10298
Daniel Veillardf06307e2001-07-03 10:35:50 +000010299 /*
10300 * Extract the old set, and then evaluate the result of the
10301 * expression for all the element in the set. use it to grow
10302 * up a new set.
10303 */
10304 CHECK_TYPE0(XPATH_NODESET);
10305 obj = valuePop(ctxt);
10306 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010307
Daniel Veillardf06307e2001-07-03 10:35:50 +000010308 oldnode = ctxt->context->node;
10309 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010310
Daniel Veillardf06307e2001-07-03 10:35:50 +000010311 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10312 ctxt->context->contextSize = 0;
10313 ctxt->context->proximityPosition = 0;
10314 if (op->ch2 != -1)
10315 total +=
10316 xmlXPathCompOpEval(ctxt,
10317 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010318 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010319 res = valuePop(ctxt);
10320 if (res != NULL)
10321 xmlXPathFreeObject(res);
10322 valuePush(ctxt, obj);
10323 ctxt->context->node = oldnode;
10324 CHECK_ERROR0;
10325 } else {
10326 /*
10327 * Initialize the new set.
10328 */
10329 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010330
Daniel Veillardf06307e2001-07-03 10:35:50 +000010331 for (i = 0; i < oldset->nodeNr; i++) {
10332 /*
10333 * Run the evaluation with a node list made of
10334 * a single item in the nodeset.
10335 */
10336 ctxt->context->node = oldset->nodeTab[i];
10337 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10338 valuePush(ctxt, tmp);
10339 ctxt->context->contextSize = oldset->nodeNr;
10340 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010341
Daniel Veillardf06307e2001-07-03 10:35:50 +000010342 if (op->ch2 != -1)
10343 total +=
10344 xmlXPathCompOpEval(ctxt,
10345 &comp->steps[op->ch2]);
10346 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010347
Daniel Veillardf06307e2001-07-03 10:35:50 +000010348 /*
10349 * The result of the evaluation need to be tested to
10350 * decided whether the filter succeeded or not
10351 */
10352 res = valuePop(ctxt);
10353 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10354 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10355 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010356
Daniel Veillardf06307e2001-07-03 10:35:50 +000010357 /*
10358 * Cleanup
10359 */
10360 if (res != NULL)
10361 xmlXPathFreeObject(res);
10362 if (ctxt->value == tmp) {
10363 res = valuePop(ctxt);
10364 xmlXPathFreeObject(res);
10365 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010366
Daniel Veillardf06307e2001-07-03 10:35:50 +000010367 ctxt->context->node = NULL;
10368 }
10369
10370 /*
10371 * The result is used as the new evaluation set.
10372 */
10373 xmlXPathFreeObject(obj);
10374 ctxt->context->node = NULL;
10375 ctxt->context->contextSize = -1;
10376 ctxt->context->proximityPosition = -1;
10377 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10378 }
10379 ctxt->context->node = oldnode;
10380 return (total);
10381 }
10382 case XPATH_OP_SORT:
10383 if (op->ch1 != -1)
10384 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010385 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010386 if ((ctxt->value != NULL) &&
10387 (ctxt->value->type == XPATH_NODESET) &&
10388 (ctxt->value->nodesetval != NULL))
10389 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10390 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010391#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010392 case XPATH_OP_RANGETO:{
10393 xmlXPathObjectPtr range;
10394 xmlXPathObjectPtr res, obj;
10395 xmlXPathObjectPtr tmp;
10396 xmlLocationSetPtr newset = NULL;
10397 xmlNodeSetPtr oldset;
10398 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010399
Daniel Veillardf06307e2001-07-03 10:35:50 +000010400 if (op->ch1 != -1)
10401 total +=
10402 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10403 if (op->ch2 == -1)
10404 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010405
Daniel Veillardf06307e2001-07-03 10:35:50 +000010406 CHECK_TYPE0(XPATH_NODESET);
10407 obj = valuePop(ctxt);
10408 oldset = obj->nodesetval;
10409 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010410
Daniel Veillardf06307e2001-07-03 10:35:50 +000010411 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010412
Daniel Veillardf06307e2001-07-03 10:35:50 +000010413 if (oldset != NULL) {
10414 for (i = 0; i < oldset->nodeNr; i++) {
10415 /*
10416 * Run the evaluation with a node list made of a single item
10417 * in the nodeset.
10418 */
10419 ctxt->context->node = oldset->nodeTab[i];
10420 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10421 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010422
Daniel Veillardf06307e2001-07-03 10:35:50 +000010423 if (op->ch2 != -1)
10424 total +=
10425 xmlXPathCompOpEval(ctxt,
10426 &comp->steps[op->ch2]);
10427 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010428
Daniel Veillardf06307e2001-07-03 10:35:50 +000010429 /*
10430 * The result of the evaluation need to be tested to
10431 * decided whether the filter succeeded or not
10432 */
10433 res = valuePop(ctxt);
10434 range =
10435 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10436 res);
10437 if (range != NULL) {
10438 xmlXPtrLocationSetAdd(newset, range);
10439 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010440
Daniel Veillardf06307e2001-07-03 10:35:50 +000010441 /*
10442 * Cleanup
10443 */
10444 if (res != NULL)
10445 xmlXPathFreeObject(res);
10446 if (ctxt->value == tmp) {
10447 res = valuePop(ctxt);
10448 xmlXPathFreeObject(res);
10449 }
10450
10451 ctxt->context->node = NULL;
10452 }
10453 }
10454
10455 /*
10456 * The result is used as the new evaluation set.
10457 */
10458 xmlXPathFreeObject(obj);
10459 ctxt->context->node = NULL;
10460 ctxt->context->contextSize = -1;
10461 ctxt->context->proximityPosition = -1;
10462 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
10463 return (total);
10464 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010465#endif /* LIBXML_XPTR_ENABLED */
10466 }
10467 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010468 "XPath: unknown precompiled operation %d\n", op->op);
10469 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010470}
10471
10472/**
10473 * xmlXPathRunEval:
10474 * @ctxt: the XPath parser context with the compiled expression
10475 *
10476 * Evaluate the Precompiled XPath expression in the given context.
10477 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010478static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010479xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10480 xmlXPathCompExprPtr comp;
10481
10482 if ((ctxt == NULL) || (ctxt->comp == NULL))
10483 return;
10484
10485 if (ctxt->valueTab == NULL) {
10486 /* Allocate the value stack */
10487 ctxt->valueTab = (xmlXPathObjectPtr *)
10488 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10489 if (ctxt->valueTab == NULL) {
10490 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010491 }
10492 ctxt->valueNr = 0;
10493 ctxt->valueMax = 10;
10494 ctxt->value = NULL;
10495 }
10496 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000010497 if(comp->last < 0) {
10498 xmlGenericError(xmlGenericErrorContext,
10499 "xmlXPathRunEval: last is less than zero\n");
10500 return;
10501 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010502 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10503}
10504
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010505/************************************************************************
10506 * *
10507 * Public interfaces *
10508 * *
10509 ************************************************************************/
10510
10511/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010512 * xmlXPathEvalPredicate:
10513 * @ctxt: the XPath context
10514 * @res: the Predicate Expression evaluation result
10515 *
10516 * Evaluate a predicate result for the current node.
10517 * A PredicateExpr is evaluated by evaluating the Expr and converting
10518 * the result to a boolean. If the result is a number, the result will
10519 * be converted to true if the number is equal to the position of the
10520 * context node in the context node list (as returned by the position
10521 * function) and will be converted to false otherwise; if the result
10522 * is not a number, then the result will be converted as if by a call
10523 * to the boolean function.
10524 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010525 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010526 */
10527int
10528xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
10529 if (res == NULL) return(0);
10530 switch (res->type) {
10531 case XPATH_BOOLEAN:
10532 return(res->boolval);
10533 case XPATH_NUMBER:
10534 return(res->floatval == ctxt->proximityPosition);
10535 case XPATH_NODESET:
10536 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010537 if (res->nodesetval == NULL)
10538 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010539 return(res->nodesetval->nodeNr != 0);
10540 case XPATH_STRING:
10541 return((res->stringval != NULL) &&
10542 (xmlStrlen(res->stringval) != 0));
10543 default:
10544 STRANGE
10545 }
10546 return(0);
10547}
10548
10549/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010550 * xmlXPathEvaluatePredicateResult:
10551 * @ctxt: the XPath Parser context
10552 * @res: the Predicate Expression evaluation result
10553 *
10554 * Evaluate a predicate result for the current node.
10555 * A PredicateExpr is evaluated by evaluating the Expr and converting
10556 * the result to a boolean. If the result is a number, the result will
10557 * be converted to true if the number is equal to the position of the
10558 * context node in the context node list (as returned by the position
10559 * function) and will be converted to false otherwise; if the result
10560 * is not a number, then the result will be converted as if by a call
10561 * to the boolean function.
10562 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010563 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010564 */
10565int
10566xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10567 xmlXPathObjectPtr res) {
10568 if (res == NULL) return(0);
10569 switch (res->type) {
10570 case XPATH_BOOLEAN:
10571 return(res->boolval);
10572 case XPATH_NUMBER:
10573 return(res->floatval == ctxt->context->proximityPosition);
10574 case XPATH_NODESET:
10575 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000010576 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000010577 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010578 return(res->nodesetval->nodeNr != 0);
10579 case XPATH_STRING:
10580 return((res->stringval != NULL) &&
10581 (xmlStrlen(res->stringval) != 0));
10582 default:
10583 STRANGE
10584 }
10585 return(0);
10586}
10587
10588/**
10589 * xmlXPathCompile:
10590 * @str: the XPath expression
10591 *
10592 * Compile an XPath expression
10593 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010594 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010595 * the caller has to free the object.
10596 */
10597xmlXPathCompExprPtr
10598xmlXPathCompile(const xmlChar *str) {
10599 xmlXPathParserContextPtr ctxt;
10600 xmlXPathCompExprPtr comp;
10601
10602 xmlXPathInit();
10603
10604 ctxt = xmlXPathNewParserContext(str, NULL);
10605 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010606
Daniel Veillard40af6492001-04-22 08:50:55 +000010607 if (*ctxt->cur != 0) {
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010608 /*
10609 * aleksey: in some cases this line prints *second* error message
10610 * (see bug #78858) and probably this should be fixed.
10611 * However, we are not sure that all error messages are printed
10612 * out in other places. It's not critical so we leave it as-is for now
10613 */
Daniel Veillard40af6492001-04-22 08:50:55 +000010614 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10615 comp = NULL;
10616 } else {
10617 comp = ctxt->comp;
10618 ctxt->comp = NULL;
10619 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010620 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010621 if (comp != NULL) {
Daniel Veillardceb09b92002-10-04 11:46:37 +000010622 comp->expr = xmlStrdup(str);
10623#ifdef DEBUG_EVAL_COUNTS
Daniel Veillardf06307e2001-07-03 10:35:50 +000010624 comp->string = xmlStrdup(str);
10625 comp->nb = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010626#endif
Daniel Veillardceb09b92002-10-04 11:46:37 +000010627 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010628 return(comp);
10629}
10630
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010631/**
10632 * xmlXPathCompiledEval:
10633 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000010634 * @ctx: the XPath context
10635 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010636 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000010637 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010638 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000010639 * the caller has to free the object.
10640 */
10641xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010642xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000010643 xmlXPathParserContextPtr ctxt;
10644 xmlXPathObjectPtr res, tmp, init = NULL;
10645 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000010646#ifndef LIBXML_THREAD_ENABLED
10647 static int reentance = 0;
10648#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010649
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010650 if ((comp == NULL) || (ctx == NULL))
10651 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010652 xmlXPathInit();
10653
10654 CHECK_CONTEXT(ctx)
10655
Daniel Veillard81463942001-10-16 12:34:39 +000010656#ifndef LIBXML_THREAD_ENABLED
10657 reentance++;
10658 if (reentance > 1)
10659 xmlXPathDisableOptimizer = 1;
10660#endif
10661
Daniel Veillardf06307e2001-07-03 10:35:50 +000010662#ifdef DEBUG_EVAL_COUNTS
10663 comp->nb++;
10664 if ((comp->string != NULL) && (comp->nb > 100)) {
10665 fprintf(stderr, "100 x %s\n", comp->string);
10666 comp->nb = 0;
10667 }
10668#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010669 ctxt = xmlXPathCompParserContext(comp, ctx);
10670 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010671
10672 if (ctxt->value == NULL) {
10673 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010674 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000010675 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000010676 } else {
10677 res = valuePop(ctxt);
10678 }
10679
Daniel Veillardf06307e2001-07-03 10:35:50 +000010680
Owen Taylor3473f882001-02-23 17:55:21 +000010681 do {
10682 tmp = valuePop(ctxt);
10683 if (tmp != NULL) {
10684 if (tmp != init)
10685 stack++;
10686 xmlXPathFreeObject(tmp);
10687 }
10688 } while (tmp != NULL);
10689 if ((stack != 0) && (res != NULL)) {
10690 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010691 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000010692 stack);
10693 }
10694 if (ctxt->error != XPATH_EXPRESSION_OK) {
10695 xmlXPathFreeObject(res);
10696 res = NULL;
10697 }
10698
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010699
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010700 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010701 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000010702#ifndef LIBXML_THREAD_ENABLED
10703 reentance--;
10704#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010705 return(res);
10706}
10707
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010708/**
10709 * xmlXPathEvalExpr:
10710 * @ctxt: the XPath Parser context
10711 *
10712 * Parse and evaluate an XPath expression in the given context,
10713 * then push the result on the context stack
10714 */
10715void
10716xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
10717 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010718 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010719 xmlXPathRunEval(ctxt);
10720}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010721
10722/**
10723 * xmlXPathEval:
10724 * @str: the XPath expression
10725 * @ctx: the XPath context
10726 *
10727 * Evaluate the XPath Location Path in the given context.
10728 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010729 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010730 * the caller has to free the object.
10731 */
10732xmlXPathObjectPtr
10733xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
10734 xmlXPathParserContextPtr ctxt;
10735 xmlXPathObjectPtr res, tmp, init = NULL;
10736 int stack = 0;
10737
10738 xmlXPathInit();
10739
10740 CHECK_CONTEXT(ctx)
10741
10742 ctxt = xmlXPathNewParserContext(str, ctx);
10743 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010744
10745 if (ctxt->value == NULL) {
10746 xmlGenericError(xmlGenericErrorContext,
10747 "xmlXPathEval: evaluation failed\n");
10748 res = NULL;
10749 } else if (*ctxt->cur != 0) {
10750 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10751 res = NULL;
10752 } else {
10753 res = valuePop(ctxt);
10754 }
10755
10756 do {
10757 tmp = valuePop(ctxt);
10758 if (tmp != NULL) {
10759 if (tmp != init)
10760 stack++;
10761 xmlXPathFreeObject(tmp);
10762 }
10763 } while (tmp != NULL);
10764 if ((stack != 0) && (res != NULL)) {
10765 xmlGenericError(xmlGenericErrorContext,
10766 "xmlXPathEval: %d object left on the stack\n",
10767 stack);
10768 }
10769 if (ctxt->error != XPATH_EXPRESSION_OK) {
10770 xmlXPathFreeObject(res);
10771 res = NULL;
10772 }
10773
Owen Taylor3473f882001-02-23 17:55:21 +000010774 xmlXPathFreeParserContext(ctxt);
10775 return(res);
10776}
10777
10778/**
10779 * xmlXPathEvalExpression:
10780 * @str: the XPath expression
10781 * @ctxt: the XPath context
10782 *
10783 * Evaluate the XPath expression in the given context.
10784 *
10785 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
10786 * the caller has to free the object.
10787 */
10788xmlXPathObjectPtr
10789xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
10790 xmlXPathParserContextPtr pctxt;
10791 xmlXPathObjectPtr res, tmp;
10792 int stack = 0;
10793
10794 xmlXPathInit();
10795
10796 CHECK_CONTEXT(ctxt)
10797
10798 pctxt = xmlXPathNewParserContext(str, ctxt);
10799 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010800
10801 if (*pctxt->cur != 0) {
10802 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10803 res = NULL;
10804 } else {
10805 res = valuePop(pctxt);
10806 }
10807 do {
10808 tmp = valuePop(pctxt);
10809 if (tmp != NULL) {
10810 xmlXPathFreeObject(tmp);
10811 stack++;
10812 }
10813 } while (tmp != NULL);
10814 if ((stack != 0) && (res != NULL)) {
10815 xmlGenericError(xmlGenericErrorContext,
10816 "xmlXPathEvalExpression: %d object left on the stack\n",
10817 stack);
10818 }
10819 xmlXPathFreeParserContext(pctxt);
10820 return(res);
10821}
10822
Daniel Veillard42766c02002-08-22 20:52:17 +000010823/************************************************************************
10824 * *
10825 * Extra functions not pertaining to the XPath spec *
10826 * *
10827 ************************************************************************/
10828/**
10829 * xmlXPathEscapeUriFunction:
10830 * @ctxt: the XPath Parser context
10831 * @nargs: the number of arguments
10832 *
10833 * Implement the escape-uri() XPath function
10834 * string escape-uri(string $str, bool $escape-reserved)
10835 *
10836 * This function applies the URI escaping rules defined in section 2 of [RFC
10837 * 2396] to the string supplied as $uri-part, which typically represents all
10838 * or part of a URI. The effect of the function is to replace any special
10839 * character in the string by an escape sequence of the form %xx%yy...,
10840 * where xxyy... is the hexadecimal representation of the octets used to
10841 * represent the character in UTF-8.
10842 *
10843 * The set of characters that are escaped depends on the setting of the
10844 * boolean argument $escape-reserved.
10845 *
10846 * If $escape-reserved is true, all characters are escaped other than lower
10847 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
10848 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
10849 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
10850 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
10851 * A-F).
10852 *
10853 * If $escape-reserved is false, the behavior differs in that characters
10854 * referred to in [RFC 2396] as reserved characters are not escaped. These
10855 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
10856 *
10857 * [RFC 2396] does not define whether escaped URIs should use lower case or
10858 * upper case for hexadecimal digits. To ensure that escaped URIs can be
10859 * compared using string comparison functions, this function must always use
10860 * the upper-case letters A-F.
10861 *
10862 * Generally, $escape-reserved should be set to true when escaping a string
10863 * that is to form a single part of a URI, and to false when escaping an
10864 * entire URI or URI reference.
10865 *
10866 * In the case of non-ascii characters, the string is encoded according to
10867 * utf-8 and then converted according to RFC 2396.
10868 *
10869 * Examples
10870 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
10871 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
10872 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
10873 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
10874 *
10875 */
Daniel Veillard118aed72002-09-24 14:13:13 +000010876static void
Daniel Veillard42766c02002-08-22 20:52:17 +000010877xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
10878 xmlXPathObjectPtr str;
10879 int escape_reserved;
10880 xmlBufferPtr target;
10881 xmlChar *cptr;
10882 xmlChar escape[4];
10883
10884 CHECK_ARITY(2);
10885
10886 escape_reserved = xmlXPathPopBoolean(ctxt);
10887
10888 CAST_TO_STRING;
10889 str = valuePop(ctxt);
10890
10891 target = xmlBufferCreate();
10892
10893 escape[0] = '%';
10894 escape[3] = 0;
10895
10896 if (target) {
10897 for (cptr = str->stringval; *cptr; cptr++) {
10898 if ((*cptr >= 'A' && *cptr <= 'Z') ||
10899 (*cptr >= 'a' && *cptr <= 'z') ||
10900 (*cptr >= '0' && *cptr <= '9') ||
10901 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
10902 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
10903 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
10904 (*cptr == '%' &&
10905 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
10906 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
10907 (cptr[1] >= '0' && cptr[1] <= '9')) &&
10908 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
10909 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
10910 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
10911 (!escape_reserved &&
10912 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
10913 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
10914 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
10915 *cptr == ','))) {
10916 xmlBufferAdd(target, cptr, 1);
10917 } else {
10918 if ((*cptr >> 4) < 10)
10919 escape[1] = '0' + (*cptr >> 4);
10920 else
10921 escape[1] = 'A' - 10 + (*cptr >> 4);
10922 if ((*cptr & 0xF) < 10)
10923 escape[2] = '0' + (*cptr & 0xF);
10924 else
10925 escape[2] = 'A' - 10 + (*cptr & 0xF);
10926
10927 xmlBufferAdd(target, &escape[0], 3);
10928 }
10929 }
10930 }
10931 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
10932 xmlBufferFree(target);
10933 xmlXPathFreeObject(str);
10934}
10935
Owen Taylor3473f882001-02-23 17:55:21 +000010936/**
10937 * xmlXPathRegisterAllFunctions:
10938 * @ctxt: the XPath context
10939 *
10940 * Registers all default XPath functions in this context
10941 */
10942void
10943xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
10944{
10945 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
10946 xmlXPathBooleanFunction);
10947 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
10948 xmlXPathCeilingFunction);
10949 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
10950 xmlXPathCountFunction);
10951 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
10952 xmlXPathConcatFunction);
10953 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
10954 xmlXPathContainsFunction);
10955 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
10956 xmlXPathIdFunction);
10957 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
10958 xmlXPathFalseFunction);
10959 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
10960 xmlXPathFloorFunction);
10961 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
10962 xmlXPathLastFunction);
10963 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
10964 xmlXPathLangFunction);
10965 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
10966 xmlXPathLocalNameFunction);
10967 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
10968 xmlXPathNotFunction);
10969 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
10970 xmlXPathNameFunction);
10971 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
10972 xmlXPathNamespaceURIFunction);
10973 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
10974 xmlXPathNormalizeFunction);
10975 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
10976 xmlXPathNumberFunction);
10977 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
10978 xmlXPathPositionFunction);
10979 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
10980 xmlXPathRoundFunction);
10981 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
10982 xmlXPathStringFunction);
10983 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
10984 xmlXPathStringLengthFunction);
10985 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
10986 xmlXPathStartsWithFunction);
10987 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
10988 xmlXPathSubstringFunction);
10989 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
10990 xmlXPathSubstringBeforeFunction);
10991 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
10992 xmlXPathSubstringAfterFunction);
10993 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
10994 xmlXPathSumFunction);
10995 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
10996 xmlXPathTrueFunction);
10997 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
10998 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000010999
11000 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
11001 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
11002 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000011003}
11004
11005#endif /* LIBXML_XPATH_ENABLED */