blob: ee339de236ac8b209e05caee444c1882a3a26be9 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * xpath.c: XML Path Language implementation
3 * XPath is a language for addressing parts of an XML document,
4 * designed to be used by both XSLT and XPointer
5 *
6 * Reference: W3C Recommendation 16 November 1999
7 * http://www.w3.org/TR/1999/REC-xpath-19991116
8 * Public reference:
9 * http://www.w3.org/TR/xpath
10 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011 * See Copyright for the status of this software
Owen Taylor3473f882001-02-23 17:55:21 +000012 *
Daniel Veillardc5d64342001-06-24 12:13:24 +000013 * Author: daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000014 *
Owen Taylor3473f882001-02-23 17:55:21 +000015 */
16
Daniel Veillard34ce8be2002-03-18 19:37:11 +000017#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000018#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000019#ifdef LIBXML_XPATH_ENABLED
20
Owen Taylor3473f882001-02-23 17:55:21 +000021#include <string.h>
22
23#ifdef HAVE_SYS_TYPES_H
24#include <sys/types.h>
25#endif
26#ifdef HAVE_MATH_H
27#include <math.h>
28#endif
29#ifdef HAVE_FLOAT_H
30#include <float.h>
31#endif
Owen Taylor3473f882001-02-23 17:55:21 +000032#ifdef HAVE_CTYPE_H
33#include <ctype.h>
34#endif
Daniel Veillard5792e162001-04-30 17:44:45 +000035#ifdef HAVE_SIGNAL_H
Daniel Veillardb45c43b2001-04-28 17:02:11 +000036#include <signal.h>
Daniel Veillardb45c43b2001-04-28 17:02:11 +000037#endif
Owen Taylor3473f882001-02-23 17:55:21 +000038
39#include <libxml/xmlmemory.h>
40#include <libxml/tree.h>
41#include <libxml/valid.h>
42#include <libxml/xpath.h>
43#include <libxml/xpathInternals.h>
44#include <libxml/parserInternals.h>
45#include <libxml/hash.h>
46#ifdef LIBXML_XPTR_ENABLED
47#include <libxml/xpointer.h>
48#endif
49#ifdef LIBXML_DEBUG_ENABLED
50#include <libxml/debugXML.h>
51#endif
52#include <libxml/xmlerror.h>
Daniel Veillard81463942001-10-16 12:34:39 +000053#include <libxml/threads.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000054#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000055
Daniel Veillard652d8a92003-02-04 19:28:49 +000056/*
57 * TODO: when compatibility allows remove all "fake node libxslt" strings
58 * the test should just be name[0] = ' '
59 */
Owen Taylor3473f882001-02-23 17:55:21 +000060/* #define DEBUG */
61/* #define DEBUG_STEP */
Daniel Veillardf06307e2001-07-03 10:35:50 +000062/* #define DEBUG_STEP_NTH */
Owen Taylor3473f882001-02-23 17:55:21 +000063/* #define DEBUG_EXPR */
Daniel Veillardf06307e2001-07-03 10:35:50 +000064/* #define DEBUG_EVAL_COUNTS */
Owen Taylor3473f882001-02-23 17:55:21 +000065
Daniel Veillard20ee8c02001-10-05 09:18:14 +000066static xmlNs xmlXPathXMLNamespaceStruct = {
67 NULL,
68 XML_NAMESPACE_DECL,
69 XML_XML_NAMESPACE,
Daniel Veillard118aed72002-09-24 14:13:13 +000070 BAD_CAST "xml",
71 NULL
Daniel Veillard20ee8c02001-10-05 09:18:14 +000072};
73static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
Daniel Veillardda423da2002-04-10 19:25:38 +000074#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +000075/*
76 * Optimizer is disabled only when threaded apps are detected while
77 * the library ain't compiled for thread safety.
78 */
79static int xmlXPathDisableOptimizer = 0;
80#endif
Daniel Veillard20ee8c02001-10-05 09:18:14 +000081
Daniel Veillard9e7160d2001-03-18 23:17:47 +000082/************************************************************************
83 * *
84 * Floating point stuff *
85 * *
86 ************************************************************************/
87
Daniel Veillardc0631a62001-09-20 13:56:06 +000088#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +000089#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +000090#endif
Daniel Veillardcda96922001-08-21 10:56:31 +000091#include "trionan.c"
92
Owen Taylor3473f882001-02-23 17:55:21 +000093/*
Owen Taylor3473f882001-02-23 17:55:21 +000094 * The lack of portability of this section of the libc is annoying !
95 */
96double xmlXPathNAN = 0;
97double xmlXPathPINF = 1;
98double xmlXPathNINF = -1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +000099double xmlXPathNZERO = 0;
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000100static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000101
Owen Taylor3473f882001-02-23 17:55:21 +0000102/**
103 * xmlXPathInit:
104 *
105 * Initialize the XPath environment
106 */
107void
108xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000109 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +0000110
Bjorn Reese45029602001-08-21 09:23:53 +0000111 xmlXPathPINF = trio_pinf();
112 xmlXPathNINF = trio_ninf();
113 xmlXPathNAN = trio_nan();
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000114 xmlXPathNZERO = trio_nzero();
Owen Taylor3473f882001-02-23 17:55:21 +0000115
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000116 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000117}
118
Daniel Veillardcda96922001-08-21 10:56:31 +0000119/**
120 * xmlXPathIsNaN:
121 * @val: a double value
122 *
123 * Provides a portable isnan() function to detect whether a double
124 * is a NotaNumber. Based on trio code
125 * http://sourceforge.net/projects/ctrio/
126 *
127 * Returns 1 if the value is a NaN, 0 otherwise
128 */
129int
130xmlXPathIsNaN(double val) {
131 return(trio_isnan(val));
132}
133
134/**
135 * xmlXPathIsInf:
136 * @val: a double value
137 *
138 * Provides a portable isinf() function to detect whether a double
139 * is a +Infinite or -Infinite. Based on trio code
140 * http://sourceforge.net/projects/ctrio/
141 *
142 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
143 */
144int
145xmlXPathIsInf(double val) {
146 return(trio_isinf(val));
147}
148
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000149/**
150 * xmlXPathGetSign:
151 * @val: a double value
152 *
153 * Provides a portable function to detect the sign of a double
154 * Modified from trio code
155 * http://sourceforge.net/projects/ctrio/
156 *
157 * Returns 1 if the value is Negative, 0 if positive
158 */
Daniel Veillard21458c82002-03-27 16:12:22 +0000159static int
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000160xmlXPathGetSign(double val) {
Daniel Veillard21458c82002-03-27 16:12:22 +0000161 return(trio_signbit(val));
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000162}
163
164
Owen Taylor3473f882001-02-23 17:55:21 +0000165/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000166 * *
167 * Parser Types *
168 * *
169 ************************************************************************/
170
171/*
172 * Types are private:
173 */
174
175typedef enum {
176 XPATH_OP_END=0,
177 XPATH_OP_AND,
178 XPATH_OP_OR,
179 XPATH_OP_EQUAL,
180 XPATH_OP_CMP,
181 XPATH_OP_PLUS,
182 XPATH_OP_MULT,
183 XPATH_OP_UNION,
184 XPATH_OP_ROOT,
185 XPATH_OP_NODE,
186 XPATH_OP_RESET,
187 XPATH_OP_COLLECT,
188 XPATH_OP_VALUE,
189 XPATH_OP_VARIABLE,
190 XPATH_OP_FUNCTION,
191 XPATH_OP_ARG,
192 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000193 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000194 XPATH_OP_SORT
195#ifdef LIBXML_XPTR_ENABLED
196 ,XPATH_OP_RANGETO
197#endif
198} xmlXPathOp;
199
200typedef enum {
201 AXIS_ANCESTOR = 1,
202 AXIS_ANCESTOR_OR_SELF,
203 AXIS_ATTRIBUTE,
204 AXIS_CHILD,
205 AXIS_DESCENDANT,
206 AXIS_DESCENDANT_OR_SELF,
207 AXIS_FOLLOWING,
208 AXIS_FOLLOWING_SIBLING,
209 AXIS_NAMESPACE,
210 AXIS_PARENT,
211 AXIS_PRECEDING,
212 AXIS_PRECEDING_SIBLING,
213 AXIS_SELF
214} xmlXPathAxisVal;
215
216typedef enum {
217 NODE_TEST_NONE = 0,
218 NODE_TEST_TYPE = 1,
219 NODE_TEST_PI = 2,
220 NODE_TEST_ALL = 3,
221 NODE_TEST_NS = 4,
222 NODE_TEST_NAME = 5
223} xmlXPathTestVal;
224
225typedef enum {
226 NODE_TYPE_NODE = 0,
227 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
228 NODE_TYPE_TEXT = XML_TEXT_NODE,
229 NODE_TYPE_PI = XML_PI_NODE
230} xmlXPathTypeVal;
231
232
233typedef struct _xmlXPathStepOp xmlXPathStepOp;
234typedef xmlXPathStepOp *xmlXPathStepOpPtr;
235struct _xmlXPathStepOp {
236 xmlXPathOp op;
237 int ch1;
238 int ch2;
239 int value;
240 int value2;
241 int value3;
242 void *value4;
243 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000244 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000245 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000246};
247
248struct _xmlXPathCompExpr {
249 int nbStep;
250 int maxStep;
251 xmlXPathStepOp *steps; /* ops for computation */
252 int last;
Daniel Veillard118aed72002-09-24 14:13:13 +0000253 xmlChar *expr;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000254#ifdef DEBUG_EVAL_COUNTS
255 int nb;
256 xmlChar *string;
257#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000258};
259
260/************************************************************************
261 * *
262 * Parser Type functions *
263 * *
264 ************************************************************************/
265
266/**
267 * xmlXPathNewCompExpr:
268 *
269 * Create a new Xpath component
270 *
271 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
272 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000273static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000274xmlXPathNewCompExpr(void) {
275 xmlXPathCompExprPtr cur;
276
277 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
278 if (cur == NULL) {
279 xmlGenericError(xmlGenericErrorContext,
280 "xmlXPathNewCompExpr : malloc failed\n");
281 return(NULL);
282 }
283 memset(cur, 0, sizeof(xmlXPathCompExpr));
284 cur->maxStep = 10;
285 cur->nbStep = 0;
286 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
287 sizeof(xmlXPathStepOp));
288 if (cur->steps == NULL) {
289 xmlGenericError(xmlGenericErrorContext,
290 "xmlXPathNewCompExpr : malloc failed\n");
291 xmlFree(cur);
292 return(NULL);
293 }
294 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
295 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000296#ifdef DEBUG_EVAL_COUNTS
297 cur->nb = 0;
298#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000299 return(cur);
300}
301
302/**
303 * xmlXPathFreeCompExpr:
304 * @comp: an XPATH comp
305 *
306 * Free up the memory allocated by @comp
307 */
308void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000309xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
310{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000311 xmlXPathStepOpPtr op;
312 int i;
313
314 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000315 return;
316 for (i = 0; i < comp->nbStep; i++) {
317 op = &comp->steps[i];
318 if (op->value4 != NULL) {
319 if (op->op == XPATH_OP_VALUE)
320 xmlXPathFreeObject(op->value4);
321 else
322 xmlFree(op->value4);
323 }
324 if (op->value5 != NULL)
325 xmlFree(op->value5);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000326 }
327 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000328 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000329 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000330#ifdef DEBUG_EVAL_COUNTS
331 if (comp->string != NULL) {
332 xmlFree(comp->string);
333 }
334#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000335 if (comp->expr != NULL) {
336 xmlFree(comp->expr);
337 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000338
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000339 xmlFree(comp);
340}
341
342/**
343 * xmlXPathCompExprAdd:
344 * @comp: the compiled expression
345 * @ch1: first child index
346 * @ch2: second child index
347 * @op: an op
348 * @value: the first int value
349 * @value2: the second int value
350 * @value3: the third int value
351 * @value4: the first string value
352 * @value5: the second string value
353 *
354 * Add an step to an XPath Compiled Expression
355 *
356 * Returns -1 in case of failure, the index otherwise
357 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000358static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000359xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
360 xmlXPathOp op, int value,
361 int value2, int value3, void *value4, void *value5) {
362 if (comp->nbStep >= comp->maxStep) {
363 xmlXPathStepOp *real;
364
365 comp->maxStep *= 2;
366 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
367 comp->maxStep * sizeof(xmlXPathStepOp));
368 if (real == NULL) {
369 comp->maxStep /= 2;
370 xmlGenericError(xmlGenericErrorContext,
371 "xmlXPathCompExprAdd : realloc failed\n");
372 return(-1);
373 }
374 comp->steps = real;
375 }
376 comp->last = comp->nbStep;
377 comp->steps[comp->nbStep].ch1 = ch1;
378 comp->steps[comp->nbStep].ch2 = ch2;
379 comp->steps[comp->nbStep].op = op;
380 comp->steps[comp->nbStep].value = value;
381 comp->steps[comp->nbStep].value2 = value2;
382 comp->steps[comp->nbStep].value3 = value3;
383 comp->steps[comp->nbStep].value4 = value4;
384 comp->steps[comp->nbStep].value5 = value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000385 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000386 return(comp->nbStep++);
387}
388
Daniel Veillardf06307e2001-07-03 10:35:50 +0000389/**
390 * xmlXPathCompSwap:
391 * @comp: the compiled expression
392 * @op: operation index
393 *
394 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000395 */
396static void
397xmlXPathCompSwap(xmlXPathStepOpPtr op) {
398 int tmp;
399
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000400#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000401 /*
402 * Since this manipulates possibly shared variables, this is
403 * disable if one detects that the library is used in a multithreaded
404 * application
405 */
406 if (xmlXPathDisableOptimizer)
407 return;
408#endif
409
Daniel Veillardf06307e2001-07-03 10:35:50 +0000410 tmp = op->ch1;
411 op->ch1 = op->ch2;
412 op->ch2 = tmp;
413}
414
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000415#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
416 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
417 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000418#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
419 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
420 (op), (val), (val2), (val3), (val4), (val5))
421
422#define PUSH_LEAVE_EXPR(op, val, val2) \
423xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
424
425#define PUSH_UNARY_EXPR(op, ch, val, val2) \
426xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
427
428#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
429xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), (val), (val2), 0 ,NULL ,NULL)
430
431/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000432 * *
433 * Debugging related functions *
434 * *
435 ************************************************************************/
436
437#define TODO \
438 xmlGenericError(xmlGenericErrorContext, \
439 "Unimplemented block at %s:%d\n", \
440 __FILE__, __LINE__);
441
442#define STRANGE \
443 xmlGenericError(xmlGenericErrorContext, \
444 "Internal error at %s:%d\n", \
445 __FILE__, __LINE__);
446
447#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000448static void
449xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000450 int i;
451 char shift[100];
452
453 for (i = 0;((i < depth) && (i < 25));i++)
454 shift[2 * i] = shift[2 * i + 1] = ' ';
455 shift[2 * i] = shift[2 * i + 1] = 0;
456 if (cur == NULL) {
457 fprintf(output, shift);
458 fprintf(output, "Node is NULL !\n");
459 return;
460
461 }
462
463 if ((cur->type == XML_DOCUMENT_NODE) ||
464 (cur->type == XML_HTML_DOCUMENT_NODE)) {
465 fprintf(output, shift);
466 fprintf(output, " /\n");
467 } else if (cur->type == XML_ATTRIBUTE_NODE)
468 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
469 else
470 xmlDebugDumpOneNode(output, cur, depth);
471}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000472static void
473xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000474 xmlNodePtr tmp;
475 int i;
476 char shift[100];
477
478 for (i = 0;((i < depth) && (i < 25));i++)
479 shift[2 * i] = shift[2 * i + 1] = ' ';
480 shift[2 * i] = shift[2 * i + 1] = 0;
481 if (cur == NULL) {
482 fprintf(output, shift);
483 fprintf(output, "Node is NULL !\n");
484 return;
485
486 }
487
488 while (cur != NULL) {
489 tmp = cur;
490 cur = cur->next;
491 xmlDebugDumpOneNode(output, tmp, depth);
492 }
493}
Owen Taylor3473f882001-02-23 17:55:21 +0000494
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000495static void
496xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000497 int i;
498 char shift[100];
499
500 for (i = 0;((i < depth) && (i < 25));i++)
501 shift[2 * i] = shift[2 * i + 1] = ' ';
502 shift[2 * i] = shift[2 * i + 1] = 0;
503
504 if (cur == NULL) {
505 fprintf(output, shift);
506 fprintf(output, "NodeSet is NULL !\n");
507 return;
508
509 }
510
Daniel Veillard911f49a2001-04-07 15:39:35 +0000511 if (cur != NULL) {
512 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
513 for (i = 0;i < cur->nodeNr;i++) {
514 fprintf(output, shift);
515 fprintf(output, "%d", i + 1);
516 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
517 }
Owen Taylor3473f882001-02-23 17:55:21 +0000518 }
519}
520
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000521static void
522xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000523 int i;
524 char shift[100];
525
526 for (i = 0;((i < depth) && (i < 25));i++)
527 shift[2 * i] = shift[2 * i + 1] = ' ';
528 shift[2 * i] = shift[2 * i + 1] = 0;
529
530 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
531 fprintf(output, shift);
532 fprintf(output, "Value Tree is NULL !\n");
533 return;
534
535 }
536
537 fprintf(output, shift);
538 fprintf(output, "%d", i + 1);
539 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
540}
Owen Taylor3473f882001-02-23 17:55:21 +0000541#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000542static void
543xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000544 int i;
545 char shift[100];
546
547 for (i = 0;((i < depth) && (i < 25));i++)
548 shift[2 * i] = shift[2 * i + 1] = ' ';
549 shift[2 * i] = shift[2 * i + 1] = 0;
550
551 if (cur == NULL) {
552 fprintf(output, shift);
553 fprintf(output, "LocationSet is NULL !\n");
554 return;
555
556 }
557
558 for (i = 0;i < cur->locNr;i++) {
559 fprintf(output, shift);
560 fprintf(output, "%d : ", i + 1);
561 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
562 }
563}
Daniel Veillard017b1082001-06-21 11:20:21 +0000564#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000565
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000566/**
567 * xmlXPathDebugDumpObject:
568 * @output: the FILE * to dump the output
569 * @cur: the object to inspect
570 * @depth: indentation level
571 *
572 * Dump the content of the object for debugging purposes
573 */
574void
575xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000576 int i;
577 char shift[100];
578
579 for (i = 0;((i < depth) && (i < 25));i++)
580 shift[2 * i] = shift[2 * i + 1] = ' ';
581 shift[2 * i] = shift[2 * i + 1] = 0;
582
583 fprintf(output, shift);
584
585 if (cur == NULL) {
586 fprintf(output, "Object is empty (NULL)\n");
587 return;
588 }
589 switch(cur->type) {
590 case XPATH_UNDEFINED:
591 fprintf(output, "Object is uninitialized\n");
592 break;
593 case XPATH_NODESET:
594 fprintf(output, "Object is a Node Set :\n");
595 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
596 break;
597 case XPATH_XSLT_TREE:
598 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000599 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000600 break;
601 case XPATH_BOOLEAN:
602 fprintf(output, "Object is a Boolean : ");
603 if (cur->boolval) fprintf(output, "true\n");
604 else fprintf(output, "false\n");
605 break;
606 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +0000607 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000608 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000609 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000610 break;
611 case -1:
612 fprintf(output, "Object is a number : -Infinity\n");
613 break;
614 default:
Daniel Veillardcda96922001-08-21 10:56:31 +0000615 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000616 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +0000617 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
618 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000619 } else {
620 fprintf(output, "Object is a number : %0g\n", cur->floatval);
621 }
622 }
Owen Taylor3473f882001-02-23 17:55:21 +0000623 break;
624 case XPATH_STRING:
625 fprintf(output, "Object is a string : ");
626 xmlDebugDumpString(output, cur->stringval);
627 fprintf(output, "\n");
628 break;
629 case XPATH_POINT:
630 fprintf(output, "Object is a point : index %d in node", cur->index);
631 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
632 fprintf(output, "\n");
633 break;
634 case XPATH_RANGE:
635 if ((cur->user2 == NULL) ||
636 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
637 fprintf(output, "Object is a collapsed range :\n");
638 fprintf(output, shift);
639 if (cur->index >= 0)
640 fprintf(output, "index %d in ", cur->index);
641 fprintf(output, "node\n");
642 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
643 depth + 1);
644 } else {
645 fprintf(output, "Object is a range :\n");
646 fprintf(output, shift);
647 fprintf(output, "From ");
648 if (cur->index >= 0)
649 fprintf(output, "index %d in ", cur->index);
650 fprintf(output, "node\n");
651 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
652 depth + 1);
653 fprintf(output, shift);
654 fprintf(output, "To ");
655 if (cur->index2 >= 0)
656 fprintf(output, "index %d in ", cur->index2);
657 fprintf(output, "node\n");
658 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
659 depth + 1);
660 fprintf(output, "\n");
661 }
662 break;
663 case XPATH_LOCATIONSET:
664#if defined(LIBXML_XPTR_ENABLED)
665 fprintf(output, "Object is a Location Set:\n");
666 xmlXPathDebugDumpLocationSet(output,
667 (xmlLocationSetPtr) cur->user, depth);
668#endif
669 break;
670 case XPATH_USERS:
671 fprintf(output, "Object is user defined\n");
672 break;
673 }
674}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000675
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000676static void
677xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000678 xmlXPathStepOpPtr op, int depth) {
679 int i;
680 char shift[100];
681
682 for (i = 0;((i < depth) && (i < 25));i++)
683 shift[2 * i] = shift[2 * i + 1] = ' ';
684 shift[2 * i] = shift[2 * i + 1] = 0;
685
686 fprintf(output, shift);
687 if (op == NULL) {
688 fprintf(output, "Step is NULL\n");
689 return;
690 }
691 switch (op->op) {
692 case XPATH_OP_END:
693 fprintf(output, "END"); break;
694 case XPATH_OP_AND:
695 fprintf(output, "AND"); break;
696 case XPATH_OP_OR:
697 fprintf(output, "OR"); break;
698 case XPATH_OP_EQUAL:
699 if (op->value)
700 fprintf(output, "EQUAL =");
701 else
702 fprintf(output, "EQUAL !=");
703 break;
704 case XPATH_OP_CMP:
705 if (op->value)
706 fprintf(output, "CMP <");
707 else
708 fprintf(output, "CMP >");
709 if (!op->value2)
710 fprintf(output, "=");
711 break;
712 case XPATH_OP_PLUS:
713 if (op->value == 0)
714 fprintf(output, "PLUS -");
715 else if (op->value == 1)
716 fprintf(output, "PLUS +");
717 else if (op->value == 2)
718 fprintf(output, "PLUS unary -");
719 else if (op->value == 3)
720 fprintf(output, "PLUS unary - -");
721 break;
722 case XPATH_OP_MULT:
723 if (op->value == 0)
724 fprintf(output, "MULT *");
725 else if (op->value == 1)
726 fprintf(output, "MULT div");
727 else
728 fprintf(output, "MULT mod");
729 break;
730 case XPATH_OP_UNION:
731 fprintf(output, "UNION"); break;
732 case XPATH_OP_ROOT:
733 fprintf(output, "ROOT"); break;
734 case XPATH_OP_NODE:
735 fprintf(output, "NODE"); break;
736 case XPATH_OP_RESET:
737 fprintf(output, "RESET"); break;
738 case XPATH_OP_SORT:
739 fprintf(output, "SORT"); break;
740 case XPATH_OP_COLLECT: {
741 xmlXPathAxisVal axis = op->value;
742 xmlXPathTestVal test = op->value2;
743 xmlXPathTypeVal type = op->value3;
744 const xmlChar *prefix = op->value4;
745 const xmlChar *name = op->value5;
746
747 fprintf(output, "COLLECT ");
748 switch (axis) {
749 case AXIS_ANCESTOR:
750 fprintf(output, " 'ancestors' "); break;
751 case AXIS_ANCESTOR_OR_SELF:
752 fprintf(output, " 'ancestors-or-self' "); break;
753 case AXIS_ATTRIBUTE:
754 fprintf(output, " 'attributes' "); break;
755 case AXIS_CHILD:
756 fprintf(output, " 'child' "); break;
757 case AXIS_DESCENDANT:
758 fprintf(output, " 'descendant' "); break;
759 case AXIS_DESCENDANT_OR_SELF:
760 fprintf(output, " 'descendant-or-self' "); break;
761 case AXIS_FOLLOWING:
762 fprintf(output, " 'following' "); break;
763 case AXIS_FOLLOWING_SIBLING:
764 fprintf(output, " 'following-siblings' "); break;
765 case AXIS_NAMESPACE:
766 fprintf(output, " 'namespace' "); break;
767 case AXIS_PARENT:
768 fprintf(output, " 'parent' "); break;
769 case AXIS_PRECEDING:
770 fprintf(output, " 'preceding' "); break;
771 case AXIS_PRECEDING_SIBLING:
772 fprintf(output, " 'preceding-sibling' "); break;
773 case AXIS_SELF:
774 fprintf(output, " 'self' "); break;
775 }
776 switch (test) {
777 case NODE_TEST_NONE:
778 fprintf(output, "'none' "); break;
779 case NODE_TEST_TYPE:
780 fprintf(output, "'type' "); break;
781 case NODE_TEST_PI:
782 fprintf(output, "'PI' "); break;
783 case NODE_TEST_ALL:
784 fprintf(output, "'all' "); break;
785 case NODE_TEST_NS:
786 fprintf(output, "'namespace' "); break;
787 case NODE_TEST_NAME:
788 fprintf(output, "'name' "); break;
789 }
790 switch (type) {
791 case NODE_TYPE_NODE:
792 fprintf(output, "'node' "); break;
793 case NODE_TYPE_COMMENT:
794 fprintf(output, "'comment' "); break;
795 case NODE_TYPE_TEXT:
796 fprintf(output, "'text' "); break;
797 case NODE_TYPE_PI:
798 fprintf(output, "'PI' "); break;
799 }
800 if (prefix != NULL)
801 fprintf(output, "%s:", prefix);
802 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +0000803 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000804 break;
805
806 }
807 case XPATH_OP_VALUE: {
808 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
809
810 fprintf(output, "ELEM ");
811 xmlXPathDebugDumpObject(output, object, 0);
812 goto finish;
813 }
814 case XPATH_OP_VARIABLE: {
815 const xmlChar *prefix = op->value5;
816 const xmlChar *name = op->value4;
817
818 if (prefix != NULL)
819 fprintf(output, "VARIABLE %s:%s", prefix, name);
820 else
821 fprintf(output, "VARIABLE %s", name);
822 break;
823 }
824 case XPATH_OP_FUNCTION: {
825 int nbargs = op->value;
826 const xmlChar *prefix = op->value5;
827 const xmlChar *name = op->value4;
828
829 if (prefix != NULL)
830 fprintf(output, "FUNCTION %s:%s(%d args)",
831 prefix, name, nbargs);
832 else
833 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
834 break;
835 }
836 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
837 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000838 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +0000839#ifdef LIBXML_XPTR_ENABLED
840 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
841#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000842 default:
843 fprintf(output, "UNKNOWN %d\n", op->op); return;
844 }
845 fprintf(output, "\n");
846finish:
847 if (op->ch1 >= 0)
848 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
849 if (op->ch2 >= 0)
850 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
851}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000852
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000853/**
854 * xmlXPathDebugDumpCompExpr:
855 * @output: the FILE * for the output
856 * @comp: the precompiled XPath expression
857 * @depth: the indentation level.
858 *
859 * Dumps the tree of the compiled XPath expression.
860 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000861void
862xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
863 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000864 int i;
865 char shift[100];
866
867 for (i = 0;((i < depth) && (i < 25));i++)
868 shift[2 * i] = shift[2 * i + 1] = ' ';
869 shift[2 * i] = shift[2 * i + 1] = 0;
870
871 fprintf(output, shift);
872
873 if (comp == NULL) {
874 fprintf(output, "Compiled Expression is NULL\n");
875 return;
876 }
877 fprintf(output, "Compiled Expression : %d elements\n",
878 comp->nbStep);
879 i = comp->last;
880 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
881}
Daniel Veillard017b1082001-06-21 11:20:21 +0000882#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000883
884/************************************************************************
885 * *
886 * Parser stacks related functions and macros *
887 * *
888 ************************************************************************/
889
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000890/**
891 * valuePop:
892 * @ctxt: an XPath evaluation context
893 *
894 * Pops the top XPath object from the value stack
895 *
896 * Returns the XPath object just removed
897 */
Daniel Veillard1c732d22002-11-30 11:22:59 +0000898extern xmlXPathObjectPtr
899valuePop(xmlXPathParserContextPtr ctxt)
900{
901 xmlXPathObjectPtr ret;
902
903 if (ctxt->valueNr <= 0)
904 return (0);
905 ctxt->valueNr--;
906 if (ctxt->valueNr > 0)
907 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
908 else
909 ctxt->value = NULL;
910 ret = ctxt->valueTab[ctxt->valueNr];
911 ctxt->valueTab[ctxt->valueNr] = 0;
912 return (ret);
913}
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000914/**
915 * valuePush:
916 * @ctxt: an XPath evaluation context
917 * @value: the XPath object
918 *
919 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000920 *
921 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000922 */
Daniel Veillard1c732d22002-11-30 11:22:59 +0000923extern int
924valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
925{
926 if (ctxt->valueNr >= ctxt->valueMax) {
927 ctxt->valueMax *= 2;
928 ctxt->valueTab =
929 (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
930 ctxt->valueMax *
931 sizeof(ctxt->valueTab[0]));
932 if (ctxt->valueTab == NULL) {
933 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
934 return (0);
935 }
936 }
937 ctxt->valueTab[ctxt->valueNr] = value;
938 ctxt->value = value;
939 return (ctxt->valueNr++);
940}
Owen Taylor3473f882001-02-23 17:55:21 +0000941
Thomas Broyerf06a3d82001-07-16 04:52:57 +0000942/**
943 * xmlXPathPopBoolean:
944 * @ctxt: an XPath parser context
945 *
946 * Pops a boolean from the stack, handling conversion if needed.
947 * Check error with #xmlXPathCheckError.
948 *
949 * Returns the boolean
950 */
951int
952xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
953 xmlXPathObjectPtr obj;
954 int ret;
955
956 obj = valuePop(ctxt);
957 if (obj == NULL) {
958 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
959 return(0);
960 }
961 ret = xmlXPathCastToBoolean(obj);
962 xmlXPathFreeObject(obj);
963 return(ret);
964}
965
966/**
967 * xmlXPathPopNumber:
968 * @ctxt: an XPath parser context
969 *
970 * Pops a number from the stack, handling conversion if needed.
971 * Check error with #xmlXPathCheckError.
972 *
973 * Returns the number
974 */
975double
976xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
977 xmlXPathObjectPtr obj;
978 double ret;
979
980 obj = valuePop(ctxt);
981 if (obj == NULL) {
982 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
983 return(0);
984 }
985 ret = xmlXPathCastToNumber(obj);
986 xmlXPathFreeObject(obj);
987 return(ret);
988}
989
990/**
991 * xmlXPathPopString:
992 * @ctxt: an XPath parser context
993 *
994 * Pops a string from the stack, handling conversion if needed.
995 * Check error with #xmlXPathCheckError.
996 *
997 * Returns the string
998 */
999xmlChar *
1000xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
1001 xmlXPathObjectPtr obj;
1002 xmlChar * ret;
1003
1004 obj = valuePop(ctxt);
1005 if (obj == NULL) {
1006 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1007 return(NULL);
1008 }
1009 ret = xmlXPathCastToString(obj);
1010 /* TODO: needs refactoring somewhere else */
1011 if (obj->stringval == ret)
1012 obj->stringval = NULL;
1013 xmlXPathFreeObject(obj);
1014 return(ret);
1015}
1016
1017/**
1018 * xmlXPathPopNodeSet:
1019 * @ctxt: an XPath parser context
1020 *
1021 * Pops a node-set from the stack, handling conversion if needed.
1022 * Check error with #xmlXPathCheckError.
1023 *
1024 * Returns the node-set
1025 */
1026xmlNodeSetPtr
1027xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
1028 xmlXPathObjectPtr obj;
1029 xmlNodeSetPtr ret;
1030
1031 if (ctxt->value == NULL) {
1032 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1033 return(NULL);
1034 }
1035 if (!xmlXPathStackIsNodeSet(ctxt)) {
1036 xmlXPathSetTypeError(ctxt);
1037 return(NULL);
1038 }
1039 obj = valuePop(ctxt);
1040 ret = obj->nodesetval;
1041 xmlXPathFreeNodeSetList(obj);
1042 return(ret);
1043}
1044
1045/**
1046 * xmlXPathPopExternal:
1047 * @ctxt: an XPath parser context
1048 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001049 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001050 * Check error with #xmlXPathCheckError.
1051 *
1052 * Returns the object
1053 */
1054void *
1055xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1056 xmlXPathObjectPtr obj;
1057 void * ret;
1058
1059 if (ctxt->value == NULL) {
1060 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1061 return(NULL);
1062 }
1063 if (ctxt->value->type != XPATH_USERS) {
1064 xmlXPathSetTypeError(ctxt);
1065 return(NULL);
1066 }
1067 obj = valuePop(ctxt);
1068 ret = obj->user;
1069 xmlXPathFreeObject(obj);
1070 return(ret);
1071}
1072
Owen Taylor3473f882001-02-23 17:55:21 +00001073/*
1074 * Macros for accessing the content. Those should be used only by the parser,
1075 * and not exported.
1076 *
1077 * Dirty macros, i.e. one need to make assumption on the context to use them
1078 *
1079 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1080 * CUR returns the current xmlChar value, i.e. a 8 bit value
1081 * in ISO-Latin or UTF-8.
1082 * This should be used internally by the parser
1083 * only to compare to ASCII values otherwise it would break when
1084 * running with UTF-8 encoding.
1085 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1086 * to compare on ASCII based substring.
1087 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1088 * strings within the parser.
1089 * CURRENT Returns the current char value, with the full decoding of
1090 * UTF-8 if we are using this mode. It returns an int.
1091 * NEXT Skip to the next character, this does the proper decoding
1092 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1093 * It returns the pointer to the current xmlChar.
1094 */
1095
1096#define CUR (*ctxt->cur)
1097#define SKIP(val) ctxt->cur += (val)
1098#define NXT(val) ctxt->cur[(val)]
1099#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001100#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1101
1102#define COPY_BUF(l,b,i,v) \
1103 if (l == 1) b[i++] = (xmlChar) v; \
1104 else i += xmlCopyChar(l,&b[i],v)
1105
1106#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001107
1108#define SKIP_BLANKS \
1109 while (IS_BLANK(*(ctxt->cur))) NEXT
1110
1111#define CURRENT (*ctxt->cur)
1112#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1113
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001114
1115#ifndef DBL_DIG
1116#define DBL_DIG 16
1117#endif
1118#ifndef DBL_EPSILON
1119#define DBL_EPSILON 1E-9
1120#endif
1121
1122#define UPPER_DOUBLE 1E9
1123#define LOWER_DOUBLE 1E-5
1124
1125#define INTEGER_DIGITS DBL_DIG
1126#define FRACTION_DIGITS (DBL_DIG + 1)
1127#define EXPONENT_DIGITS (3 + 2)
1128
1129/**
1130 * xmlXPathFormatNumber:
1131 * @number: number to format
1132 * @buffer: output buffer
1133 * @buffersize: size of output buffer
1134 *
1135 * Convert the number into a string representation.
1136 */
1137static void
1138xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1139{
Daniel Veillardcda96922001-08-21 10:56:31 +00001140 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001141 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001142 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001143 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001144 break;
1145 case -1:
1146 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001147 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001148 break;
1149 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001150 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001151 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001152 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001153 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001154 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001155 } else if (number == ((int) number)) {
1156 char work[30];
1157 char *ptr, *cur;
1158 int res, value = (int) number;
1159
1160 ptr = &buffer[0];
1161 if (value < 0) {
1162 *ptr++ = '-';
1163 value = -value;
1164 }
1165 if (value == 0) {
1166 *ptr++ = '0';
1167 } else {
1168 cur = &work[0];
1169 while (value != 0) {
1170 res = value % 10;
1171 value = value / 10;
1172 *cur++ = '0' + res;
1173 }
1174 cur--;
1175 while ((cur >= &work[0]) && (ptr - buffer < buffersize)) {
1176 *ptr++ = *cur--;
1177 }
1178 }
1179 if (ptr - buffer < buffersize) {
1180 *ptr = 0;
1181 } else if (buffersize > 0) {
1182 ptr--;
1183 *ptr = 0;
1184 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001185 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001186 /* 3 is sign, decimal point, and terminating zero */
1187 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1188 int integer_place, fraction_place;
1189 char *ptr;
1190 char *after_fraction;
1191 double absolute_value;
1192 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001193
Bjorn Reese70a9da52001-04-21 16:57:29 +00001194 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001195
Bjorn Reese70a9da52001-04-21 16:57:29 +00001196 /*
1197 * First choose format - scientific or regular floating point.
1198 * In either case, result is in work, and after_fraction points
1199 * just past the fractional part.
1200 */
1201 if ( ((absolute_value > UPPER_DOUBLE) ||
1202 (absolute_value < LOWER_DOUBLE)) &&
1203 (absolute_value != 0.0) ) {
1204 /* Use scientific notation */
1205 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1206 fraction_place = DBL_DIG - 1;
1207 snprintf(work, sizeof(work),"%*.*e",
1208 integer_place, fraction_place, number);
1209 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001210 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001211 else {
1212 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001213 if (absolute_value > 0.0)
1214 integer_place = 1 + (int)log10(absolute_value);
1215 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001216 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001217 fraction_place = (integer_place > 0)
1218 ? DBL_DIG - integer_place
1219 : DBL_DIG;
1220 size = snprintf(work, sizeof(work), "%0.*f",
1221 fraction_place, number);
1222 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001223 }
1224
Bjorn Reese70a9da52001-04-21 16:57:29 +00001225 /* Remove fractional trailing zeroes */
1226 ptr = after_fraction;
1227 while (*(--ptr) == '0')
1228 ;
1229 if (*ptr != '.')
1230 ptr++;
1231 strcpy(ptr, after_fraction);
1232
1233 /* Finally copy result back to caller */
1234 size = strlen(work) + 1;
1235 if (size > buffersize) {
1236 work[buffersize - 1] = 0;
1237 size = buffersize;
1238 }
1239 memcpy(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001240 }
1241 break;
1242 }
1243}
1244
Owen Taylor3473f882001-02-23 17:55:21 +00001245/************************************************************************
1246 * *
1247 * Error handling routines *
1248 * *
1249 ************************************************************************/
1250
1251
Daniel Veillardb44025c2001-10-11 22:55:55 +00001252static const char *xmlXPathErrorMessages[] = {
Owen Taylor3473f882001-02-23 17:55:21 +00001253 "Ok",
1254 "Number encoding",
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001255 "Unfinished literal",
1256 "Start of literal",
Owen Taylor3473f882001-02-23 17:55:21 +00001257 "Expected $ for variable reference",
1258 "Undefined variable",
1259 "Invalid predicate",
1260 "Invalid expression",
1261 "Missing closing curly brace",
1262 "Unregistered function",
1263 "Invalid operand",
1264 "Invalid type",
1265 "Invalid number of arguments",
1266 "Invalid context size",
1267 "Invalid context position",
1268 "Memory allocation error",
1269 "Syntax error",
1270 "Resource error",
1271 "Sub resource error",
Daniel Veillard61d80a22001-04-27 17:13:01 +00001272 "Undefined namespace prefix",
1273 "Encoding error",
1274 "Char out of XML range"
Owen Taylor3473f882001-02-23 17:55:21 +00001275};
1276
1277/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001278 * xmlXPatherror:
Owen Taylor3473f882001-02-23 17:55:21 +00001279 * @ctxt: the XPath Parser context
1280 * @file: the file name
1281 * @line: the line number
1282 * @no: the error number
1283 *
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001284 * Formats an error message.
Owen Taylor3473f882001-02-23 17:55:21 +00001285 */
1286void
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00001287xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
1288 int line ATTRIBUTE_UNUSED, int no) {
Owen Taylor3473f882001-02-23 17:55:21 +00001289 int n;
1290 const xmlChar *cur;
1291 const xmlChar *base;
1292
Owen Taylor3473f882001-02-23 17:55:21 +00001293 cur = ctxt->cur;
1294 base = ctxt->base;
Daniel Veillard118aed72002-09-24 14:13:13 +00001295 if ((cur == NULL) || (base == NULL)) {
1296 if ((ctxt->comp != NULL) && (ctxt->comp->expr != NULL)) {
1297 xmlGenericError(xmlGenericErrorContext,
1298 "XPath error %s in %s\n", xmlXPathErrorMessages[no],
1299 ctxt->comp->expr);
1300 } else {
1301 xmlGenericError(xmlGenericErrorContext,
1302 "XPath error %s\n", xmlXPathErrorMessages[no]);
1303 }
1304
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001305 return;
Daniel Veillard118aed72002-09-24 14:13:13 +00001306 }
1307 xmlGenericError(xmlGenericErrorContext,
1308 "XPath error %s\n", xmlXPathErrorMessages[no]);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001309
Owen Taylor3473f882001-02-23 17:55:21 +00001310 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
1311 cur--;
1312 }
1313 n = 0;
1314 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
1315 cur--;
1316 if ((*cur == '\n') || (*cur == '\r')) cur++;
1317 base = cur;
1318 n = 0;
1319 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
1320 xmlGenericError(xmlGenericErrorContext, "%c", (unsigned char) *cur++);
1321 n++;
1322 }
1323 xmlGenericError(xmlGenericErrorContext, "\n");
1324 cur = ctxt->cur;
1325 while ((*cur == '\n') || (*cur == '\r'))
1326 cur--;
1327 n = 0;
1328 while ((cur != base) && (n++ < 80)) {
1329 xmlGenericError(xmlGenericErrorContext, " ");
1330 base++;
1331 }
1332 xmlGenericError(xmlGenericErrorContext,"^\n");
1333}
1334
1335
1336/************************************************************************
1337 * *
1338 * Routines to handle NodeSets *
1339 * *
1340 ************************************************************************/
1341
1342/**
1343 * xmlXPathCmpNodes:
1344 * @node1: the first node
1345 * @node2: the second node
1346 *
1347 * Compare two nodes w.r.t document order
1348 *
1349 * Returns -2 in case of error 1 if first point < second point, 0 if
1350 * that's the same node, -1 otherwise
1351 */
1352int
1353xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1354 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001355 int attr1 = 0, attr2 = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001356 xmlNodePtr cur, root;
1357
1358 if ((node1 == NULL) || (node2 == NULL))
1359 return(-2);
1360 /*
1361 * a couple of optimizations which will avoid computations in most cases
1362 */
Daniel Veillardedfd5882003-03-07 14:20:40 +00001363 if (node1->type == XML_ATTRIBUTE_NODE) {
1364 attr1 = 1;
1365 node1 = node1->parent;
1366 }
1367 if (node2->type == XML_ATTRIBUTE_NODE) {
1368 attr2 = 1;
1369 node2 = node2->parent;
1370 }
1371 if (node1 == node2) {
1372 if (attr1 == attr2)
1373 return(0);
1374 if (attr2 == 1)
1375 return(1);
1376 return(-1);
1377 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00001378 if ((node1->type == XML_NAMESPACE_DECL) ||
1379 (node2->type == XML_NAMESPACE_DECL))
1380 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001381 if (node1 == node2->prev)
1382 return(1);
1383 if (node1 == node2->next)
1384 return(-1);
1385
Daniel Veillard68e9e742002-11-16 15:35:11 +00001386#if 0
1387 Unfortunately this does not work. Line number in entities reset
1388 to 1 within the entity :-(
1389
Owen Taylor3473f882001-02-23 17:55:21 +00001390 /*
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001391 * Speedup using line numbers if availble.
1392 */
1393 if ((node1->type == XML_ELEMENT_NODE) &&
1394 (node2->type == XML_ELEMENT_NODE) &&
1395 (0 != (int) node1->content) && (0 != (int) node2->content)) {
1396 int l1, l2;
1397 l1 = (int) node1->content;
1398 l2 = (int) node2->content;
1399 if (l1 < l2)
1400 return(1);
1401 if (l1 > l2)
1402 return(-1);
1403 }
Daniel Veillard68e9e742002-11-16 15:35:11 +00001404#endif
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001405 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001406 * compute depth to root
1407 */
1408 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1409 if (cur == node1)
1410 return(1);
1411 depth2++;
1412 }
1413 root = cur;
1414 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1415 if (cur == node2)
1416 return(-1);
1417 depth1++;
1418 }
1419 /*
1420 * Distinct document (or distinct entities :-( ) case.
1421 */
1422 if (root != cur) {
1423 return(-2);
1424 }
1425 /*
1426 * get the nearest common ancestor.
1427 */
1428 while (depth1 > depth2) {
1429 depth1--;
1430 node1 = node1->parent;
1431 }
1432 while (depth2 > depth1) {
1433 depth2--;
1434 node2 = node2->parent;
1435 }
1436 while (node1->parent != node2->parent) {
1437 node1 = node1->parent;
1438 node2 = node2->parent;
1439 /* should not happen but just in case ... */
1440 if ((node1 == NULL) || (node2 == NULL))
1441 return(-2);
1442 }
1443 /*
1444 * Find who's first.
1445 */
1446 if (node1 == node2->next)
1447 return(-1);
1448 for (cur = node1->next;cur != NULL;cur = cur->next)
1449 if (cur == node2)
1450 return(1);
1451 return(-1); /* assume there is no sibling list corruption */
1452}
1453
1454/**
1455 * xmlXPathNodeSetSort:
1456 * @set: the node set
1457 *
1458 * Sort the node set in document order
1459 */
1460void
1461xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001462 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001463 xmlNodePtr tmp;
1464
1465 if (set == NULL)
1466 return;
1467
1468 /* Use Shell's sort to sort the node-set */
1469 len = set->nodeNr;
1470 for (incr = len / 2; incr > 0; incr /= 2) {
1471 for (i = incr; i < len; i++) {
1472 j = i - incr;
1473 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001474 if (xmlXPathCmpNodes(set->nodeTab[j],
1475 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001476 tmp = set->nodeTab[j];
1477 set->nodeTab[j] = set->nodeTab[j + incr];
1478 set->nodeTab[j + incr] = tmp;
1479 j -= incr;
1480 } else
1481 break;
1482 }
1483 }
1484 }
1485}
1486
1487#define XML_NODESET_DEFAULT 10
1488/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001489 * xmlXPathNodeSetDupNs:
1490 * @node: the parent node of the namespace XPath node
1491 * @ns: the libxml namespace declaration node.
1492 *
1493 * Namespace node in libxml don't match the XPath semantic. In a node set
1494 * the namespace nodes are duplicated and the next pointer is set to the
1495 * parent node in the XPath semantic.
1496 *
1497 * Returns the newly created object.
1498 */
1499static xmlNodePtr
1500xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
1501 xmlNsPtr cur;
1502
1503 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1504 return(NULL);
1505 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
1506 return((xmlNodePtr) ns);
1507
1508 /*
1509 * Allocate a new Namespace and fill the fields.
1510 */
1511 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1512 if (cur == NULL) {
1513 xmlGenericError(xmlGenericErrorContext,
1514 "xmlXPathNodeSetDupNs : malloc failed\n");
1515 return(NULL);
1516 }
1517 memset(cur, 0, sizeof(xmlNs));
1518 cur->type = XML_NAMESPACE_DECL;
1519 if (ns->href != NULL)
1520 cur->href = xmlStrdup(ns->href);
1521 if (ns->prefix != NULL)
1522 cur->prefix = xmlStrdup(ns->prefix);
1523 cur->next = (xmlNsPtr) node;
1524 return((xmlNodePtr) cur);
1525}
1526
1527/**
1528 * xmlXPathNodeSetFreeNs:
1529 * @ns: the XPath namespace node found in a nodeset.
1530 *
1531 * Namespace node in libxml don't match the XPath semantic. In a node set
1532 * the namespace nodes are duplicated and the next pointer is set to the
1533 * parent node in the XPath semantic. Check if such a node need to be freed
1534 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001535void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001536xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
1537 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1538 return;
1539
1540 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
1541 if (ns->href != NULL)
1542 xmlFree((xmlChar *)ns->href);
1543 if (ns->prefix != NULL)
1544 xmlFree((xmlChar *)ns->prefix);
1545 xmlFree(ns);
1546 }
1547}
1548
1549/**
Owen Taylor3473f882001-02-23 17:55:21 +00001550 * xmlXPathNodeSetCreate:
1551 * @val: an initial xmlNodePtr, or NULL
1552 *
1553 * Create a new xmlNodeSetPtr of type double and of value @val
1554 *
1555 * Returns the newly created object.
1556 */
1557xmlNodeSetPtr
1558xmlXPathNodeSetCreate(xmlNodePtr val) {
1559 xmlNodeSetPtr ret;
1560
1561 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1562 if (ret == NULL) {
1563 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001564 "xmlXPathNodeSetCreate: out of memory\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001565 return(NULL);
1566 }
1567 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1568 if (val != NULL) {
1569 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1570 sizeof(xmlNodePtr));
1571 if (ret->nodeTab == NULL) {
1572 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001573 "xmlXPathNodeSetCreate: out of memory\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001574 return(NULL);
1575 }
1576 memset(ret->nodeTab, 0 ,
1577 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1578 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001579 if (val->type == XML_NAMESPACE_DECL) {
1580 xmlNsPtr ns = (xmlNsPtr) val;
1581
1582 ret->nodeTab[ret->nodeNr++] =
1583 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1584 } else
1585 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001586 }
1587 return(ret);
1588}
1589
1590/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001591 * xmlXPathNodeSetContains:
1592 * @cur: the node-set
1593 * @val: the node
1594 *
1595 * checks whether @cur contains @val
1596 *
1597 * Returns true (1) if @cur contains @val, false (0) otherwise
1598 */
1599int
1600xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1601 int i;
1602
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001603 if (val->type == XML_NAMESPACE_DECL) {
1604 for (i = 0; i < cur->nodeNr; i++) {
1605 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1606 xmlNsPtr ns1, ns2;
1607
1608 ns1 = (xmlNsPtr) val;
1609 ns2 = (xmlNsPtr) cur->nodeTab[i];
1610 if (ns1 == ns2)
1611 return(1);
1612 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
1613 (xmlStrEqual(ns1->prefix, ns2->prefix)))
1614 return(1);
1615 }
1616 }
1617 } else {
1618 for (i = 0; i < cur->nodeNr; i++) {
1619 if (cur->nodeTab[i] == val)
1620 return(1);
1621 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001622 }
1623 return(0);
1624}
1625
1626/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001627 * xmlXPathNodeSetAddNs:
1628 * @cur: the initial node set
1629 * @node: the hosting node
1630 * @ns: a the namespace node
1631 *
1632 * add a new namespace node to an existing NodeSet
1633 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00001634void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001635xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
1636 int i;
1637
1638 if ((ns == NULL) || (node == NULL) || (ns->type != XML_NAMESPACE_DECL) ||
1639 (node->type != XML_ELEMENT_NODE))
1640 return;
1641
1642 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1643 /*
1644 * check against doublons
1645 */
1646 for (i = 0;i < cur->nodeNr;i++) {
1647 if ((cur->nodeTab[i] != NULL) &&
1648 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00001649 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001650 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
1651 return;
1652 }
1653
1654 /*
1655 * grow the nodeTab if needed
1656 */
1657 if (cur->nodeMax == 0) {
1658 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1659 sizeof(xmlNodePtr));
1660 if (cur->nodeTab == NULL) {
1661 xmlGenericError(xmlGenericErrorContext,
1662 "xmlXPathNodeSetAdd: out of memory\n");
1663 return;
1664 }
1665 memset(cur->nodeTab, 0 ,
1666 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1667 cur->nodeMax = XML_NODESET_DEFAULT;
1668 } else if (cur->nodeNr == cur->nodeMax) {
1669 xmlNodePtr *temp;
1670
1671 cur->nodeMax *= 2;
1672 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1673 sizeof(xmlNodePtr));
1674 if (temp == NULL) {
1675 xmlGenericError(xmlGenericErrorContext,
1676 "xmlXPathNodeSetAdd: out of memory\n");
1677 return;
1678 }
1679 cur->nodeTab = temp;
1680 }
1681 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
1682}
1683
1684/**
Owen Taylor3473f882001-02-23 17:55:21 +00001685 * xmlXPathNodeSetAdd:
1686 * @cur: the initial node set
1687 * @val: a new xmlNodePtr
1688 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001689 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00001690 */
1691void
1692xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1693 int i;
1694
1695 if (val == NULL) return;
1696
Daniel Veillardef0b4502003-03-24 13:57:34 +00001697#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001698 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1699 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001700#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001701
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001702 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001703 /*
1704 * check against doublons
1705 */
1706 for (i = 0;i < cur->nodeNr;i++)
1707 if (cur->nodeTab[i] == val) return;
1708
1709 /*
1710 * grow the nodeTab if needed
1711 */
1712 if (cur->nodeMax == 0) {
1713 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1714 sizeof(xmlNodePtr));
1715 if (cur->nodeTab == NULL) {
1716 xmlGenericError(xmlGenericErrorContext,
1717 "xmlXPathNodeSetAdd: out of memory\n");
1718 return;
1719 }
1720 memset(cur->nodeTab, 0 ,
1721 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1722 cur->nodeMax = XML_NODESET_DEFAULT;
1723 } else if (cur->nodeNr == cur->nodeMax) {
1724 xmlNodePtr *temp;
1725
1726 cur->nodeMax *= 2;
1727 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1728 sizeof(xmlNodePtr));
1729 if (temp == NULL) {
1730 xmlGenericError(xmlGenericErrorContext,
1731 "xmlXPathNodeSetAdd: out of memory\n");
1732 return;
1733 }
1734 cur->nodeTab = temp;
1735 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001736 if (val->type == XML_NAMESPACE_DECL) {
1737 xmlNsPtr ns = (xmlNsPtr) val;
1738
1739 cur->nodeTab[cur->nodeNr++] =
1740 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1741 } else
1742 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001743}
1744
1745/**
1746 * xmlXPathNodeSetAddUnique:
1747 * @cur: the initial node set
1748 * @val: a new xmlNodePtr
1749 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001750 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00001751 * when we are sure the node is not already in the set.
1752 */
1753void
1754xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1755 if (val == NULL) return;
1756
Daniel Veillardef0b4502003-03-24 13:57:34 +00001757#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001758 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1759 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001760#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001761
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001762 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001763 /*
1764 * grow the nodeTab if needed
1765 */
1766 if (cur->nodeMax == 0) {
1767 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1768 sizeof(xmlNodePtr));
1769 if (cur->nodeTab == NULL) {
1770 xmlGenericError(xmlGenericErrorContext,
1771 "xmlXPathNodeSetAddUnique: out of memory\n");
1772 return;
1773 }
1774 memset(cur->nodeTab, 0 ,
1775 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1776 cur->nodeMax = XML_NODESET_DEFAULT;
1777 } else if (cur->nodeNr == cur->nodeMax) {
1778 xmlNodePtr *temp;
1779
1780 cur->nodeMax *= 2;
1781 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1782 sizeof(xmlNodePtr));
1783 if (temp == NULL) {
1784 xmlGenericError(xmlGenericErrorContext,
1785 "xmlXPathNodeSetAddUnique: out of memory\n");
1786 return;
1787 }
1788 cur->nodeTab = temp;
1789 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001790 if (val->type == XML_NAMESPACE_DECL) {
1791 xmlNsPtr ns = (xmlNsPtr) val;
1792
1793 cur->nodeTab[cur->nodeNr++] =
1794 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1795 } else
1796 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001797}
1798
1799/**
1800 * xmlXPathNodeSetMerge:
1801 * @val1: the first NodeSet or NULL
1802 * @val2: the second NodeSet
1803 *
1804 * Merges two nodesets, all nodes from @val2 are added to @val1
1805 * if @val1 is NULL, a new set is created and copied from @val2
1806 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001807 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00001808 */
1809xmlNodeSetPtr
1810xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001811 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001812
1813 if (val2 == NULL) return(val1);
1814 if (val1 == NULL) {
1815 val1 = xmlXPathNodeSetCreate(NULL);
1816 }
1817
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001818 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001819 initNr = val1->nodeNr;
1820
1821 for (i = 0;i < val2->nodeNr;i++) {
1822 /*
1823 * check against doublons
1824 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001825 skip = 0;
1826 for (j = 0; j < initNr; j++) {
1827 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1828 skip = 1;
1829 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001830 } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) &&
1831 (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) {
1832 xmlNsPtr ns1, ns2;
1833 ns1 = (xmlNsPtr) val1->nodeTab[j];
1834 ns2 = (xmlNsPtr) val2->nodeTab[i];
1835 if ((ns1->next == ns2->next) &&
1836 (xmlStrEqual(ns1->prefix, ns2->prefix))) {
1837 skip = 1;
1838 break;
1839 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001840 }
1841 }
1842 if (skip)
1843 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00001844
1845 /*
1846 * grow the nodeTab if needed
1847 */
1848 if (val1->nodeMax == 0) {
1849 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1850 sizeof(xmlNodePtr));
1851 if (val1->nodeTab == NULL) {
1852 xmlGenericError(xmlGenericErrorContext,
1853 "xmlXPathNodeSetMerge: out of memory\n");
1854 return(NULL);
1855 }
1856 memset(val1->nodeTab, 0 ,
1857 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1858 val1->nodeMax = XML_NODESET_DEFAULT;
1859 } else if (val1->nodeNr == val1->nodeMax) {
1860 xmlNodePtr *temp;
1861
1862 val1->nodeMax *= 2;
1863 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1864 sizeof(xmlNodePtr));
1865 if (temp == NULL) {
1866 xmlGenericError(xmlGenericErrorContext,
1867 "xmlXPathNodeSetMerge: out of memory\n");
1868 return(NULL);
1869 }
1870 val1->nodeTab = temp;
1871 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001872 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1873 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1874
1875 val1->nodeTab[val1->nodeNr++] =
1876 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1877 } else
1878 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00001879 }
1880
1881 return(val1);
1882}
1883
1884/**
Daniel Veillard75be0132002-03-13 10:03:35 +00001885 * xmlXPathNodeSetMergeUnique:
1886 * @val1: the first NodeSet or NULL
1887 * @val2: the second NodeSet
1888 *
1889 * Merges two nodesets, all nodes from @val2 are added to @val1
1890 * if @val1 is NULL, a new set is created and copied from @val2
1891 *
1892 * Returns @val1 once extended or NULL in case of error.
1893 */
1894static xmlNodeSetPtr
1895xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
1896 int i, initNr;
1897
1898 if (val2 == NULL) return(val1);
1899 if (val1 == NULL) {
1900 val1 = xmlXPathNodeSetCreate(NULL);
1901 }
1902
1903 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1904 initNr = val1->nodeNr;
1905
1906 for (i = 0;i < val2->nodeNr;i++) {
1907 /*
1908 * grow the nodeTab if needed
1909 */
1910 if (val1->nodeMax == 0) {
1911 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1912 sizeof(xmlNodePtr));
1913 if (val1->nodeTab == NULL) {
1914 xmlGenericError(xmlGenericErrorContext,
1915 "xmlXPathNodeSetMerge: out of memory\n");
1916 return(NULL);
1917 }
1918 memset(val1->nodeTab, 0 ,
1919 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1920 val1->nodeMax = XML_NODESET_DEFAULT;
1921 } else if (val1->nodeNr == val1->nodeMax) {
1922 xmlNodePtr *temp;
1923
1924 val1->nodeMax *= 2;
1925 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1926 sizeof(xmlNodePtr));
1927 if (temp == NULL) {
1928 xmlGenericError(xmlGenericErrorContext,
1929 "xmlXPathNodeSetMerge: out of memory\n");
1930 return(NULL);
1931 }
1932 val1->nodeTab = temp;
1933 }
1934 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1935 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1936
1937 val1->nodeTab[val1->nodeNr++] =
1938 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1939 } else
1940 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
1941 }
1942
1943 return(val1);
1944}
1945
1946/**
Owen Taylor3473f882001-02-23 17:55:21 +00001947 * xmlXPathNodeSetDel:
1948 * @cur: the initial node set
1949 * @val: an xmlNodePtr
1950 *
1951 * Removes an xmlNodePtr from an existing NodeSet
1952 */
1953void
1954xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
1955 int i;
1956
1957 if (cur == NULL) return;
1958 if (val == NULL) return;
1959
1960 /*
1961 * check against doublons
1962 */
1963 for (i = 0;i < cur->nodeNr;i++)
1964 if (cur->nodeTab[i] == val) break;
1965
1966 if (i >= cur->nodeNr) {
1967#ifdef DEBUG
1968 xmlGenericError(xmlGenericErrorContext,
1969 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
1970 val->name);
1971#endif
1972 return;
1973 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001974 if ((cur->nodeTab[i] != NULL) &&
1975 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
1976 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001977 cur->nodeNr--;
1978 for (;i < cur->nodeNr;i++)
1979 cur->nodeTab[i] = cur->nodeTab[i + 1];
1980 cur->nodeTab[cur->nodeNr] = NULL;
1981}
1982
1983/**
1984 * xmlXPathNodeSetRemove:
1985 * @cur: the initial node set
1986 * @val: the index to remove
1987 *
1988 * Removes an entry from an existing NodeSet list.
1989 */
1990void
1991xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
1992 if (cur == NULL) return;
1993 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001994 if ((cur->nodeTab[val] != NULL) &&
1995 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
1996 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00001997 cur->nodeNr--;
1998 for (;val < cur->nodeNr;val++)
1999 cur->nodeTab[val] = cur->nodeTab[val + 1];
2000 cur->nodeTab[cur->nodeNr] = NULL;
2001}
2002
2003/**
2004 * xmlXPathFreeNodeSet:
2005 * @obj: the xmlNodeSetPtr to free
2006 *
2007 * Free the NodeSet compound (not the actual nodes !).
2008 */
2009void
2010xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
2011 if (obj == NULL) return;
2012 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002013 int i;
2014
2015 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
2016 for (i = 0;i < obj->nodeNr;i++)
2017 if ((obj->nodeTab[i] != NULL) &&
2018 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
2019 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
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/**
2026 * xmlXPathFreeValueTree:
2027 * @obj: the xmlNodeSetPtr to free
2028 *
2029 * Free the NodeSet compound and the actual tree, this is different
2030 * from xmlXPathFreeNodeSet()
2031 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002032static void
Owen Taylor3473f882001-02-23 17:55:21 +00002033xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
2034 int i;
2035
2036 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002037
2038 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002039 for (i = 0;i < obj->nodeNr;i++) {
2040 if (obj->nodeTab[i] != NULL) {
2041 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2042 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
2043 } else {
2044 xmlFreeNodeList(obj->nodeTab[i]);
2045 }
2046 }
2047 }
Owen Taylor3473f882001-02-23 17:55:21 +00002048 xmlFree(obj->nodeTab);
2049 }
Owen Taylor3473f882001-02-23 17:55:21 +00002050 xmlFree(obj);
2051}
2052
2053#if defined(DEBUG) || defined(DEBUG_STEP)
2054/**
2055 * xmlGenericErrorContextNodeSet:
2056 * @output: a FILE * for the output
2057 * @obj: the xmlNodeSetPtr to free
2058 *
2059 * Quick display of a NodeSet
2060 */
2061void
2062xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
2063 int i;
2064
2065 if (output == NULL) output = xmlGenericErrorContext;
2066 if (obj == NULL) {
2067 fprintf(output, "NodeSet == NULL !\n");
2068 return;
2069 }
2070 if (obj->nodeNr == 0) {
2071 fprintf(output, "NodeSet is empty\n");
2072 return;
2073 }
2074 if (obj->nodeTab == NULL) {
2075 fprintf(output, " nodeTab == NULL !\n");
2076 return;
2077 }
2078 for (i = 0; i < obj->nodeNr; i++) {
2079 if (obj->nodeTab[i] == NULL) {
2080 fprintf(output, " NULL !\n");
2081 return;
2082 }
2083 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
2084 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
2085 fprintf(output, " /");
2086 else if (obj->nodeTab[i]->name == NULL)
2087 fprintf(output, " noname!");
2088 else fprintf(output, " %s", obj->nodeTab[i]->name);
2089 }
2090 fprintf(output, "\n");
2091}
2092#endif
2093
2094/**
2095 * xmlXPathNewNodeSet:
2096 * @val: the NodePtr value
2097 *
2098 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2099 * it with the single Node @val
2100 *
2101 * Returns the newly created object.
2102 */
2103xmlXPathObjectPtr
2104xmlXPathNewNodeSet(xmlNodePtr val) {
2105 xmlXPathObjectPtr ret;
2106
2107 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2108 if (ret == NULL) {
2109 xmlGenericError(xmlGenericErrorContext,
2110 "xmlXPathNewNodeSet: out of memory\n");
2111 return(NULL);
2112 }
2113 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2114 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00002115 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002116 ret->nodesetval = xmlXPathNodeSetCreate(val);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002117 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002118 return(ret);
2119}
2120
2121/**
2122 * xmlXPathNewValueTree:
2123 * @val: the NodePtr value
2124 *
2125 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
2126 * it with the tree root @val
2127 *
2128 * Returns the newly created object.
2129 */
2130xmlXPathObjectPtr
2131xmlXPathNewValueTree(xmlNodePtr val) {
2132 xmlXPathObjectPtr ret;
2133
2134 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2135 if (ret == NULL) {
2136 xmlGenericError(xmlGenericErrorContext,
2137 "xmlXPathNewNodeSet: out of memory\n");
2138 return(NULL);
2139 }
2140 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2141 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002142 ret->boolval = 1;
2143 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00002144 ret->nodesetval = xmlXPathNodeSetCreate(val);
2145 return(ret);
2146}
2147
2148/**
2149 * xmlXPathNewNodeSetList:
2150 * @val: an existing NodeSet
2151 *
2152 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2153 * it with the Nodeset @val
2154 *
2155 * Returns the newly created object.
2156 */
2157xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002158xmlXPathNewNodeSetList(xmlNodeSetPtr val)
2159{
Owen Taylor3473f882001-02-23 17:55:21 +00002160 xmlXPathObjectPtr ret;
2161 int i;
2162
2163 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002164 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002165 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002166 ret = xmlXPathNewNodeSet(NULL);
2167 else {
2168 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
2169 for (i = 1; i < val->nodeNr; ++i)
2170 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2171 }
Owen Taylor3473f882001-02-23 17:55:21 +00002172
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002173 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002174}
2175
2176/**
2177 * xmlXPathWrapNodeSet:
2178 * @val: the NodePtr value
2179 *
2180 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2181 *
2182 * Returns the newly created object.
2183 */
2184xmlXPathObjectPtr
2185xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2186 xmlXPathObjectPtr ret;
2187
2188 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2189 if (ret == NULL) {
2190 xmlGenericError(xmlGenericErrorContext,
2191 "xmlXPathWrapNodeSet: out of memory\n");
2192 return(NULL);
2193 }
2194 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2195 ret->type = XPATH_NODESET;
2196 ret->nodesetval = val;
2197 return(ret);
2198}
2199
2200/**
2201 * xmlXPathFreeNodeSetList:
2202 * @obj: an existing NodeSetList object
2203 *
2204 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2205 * the list contrary to xmlXPathFreeObject().
2206 */
2207void
2208xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2209 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002210 xmlFree(obj);
2211}
2212
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002213/**
2214 * xmlXPathDifference:
2215 * @nodes1: a node-set
2216 * @nodes2: a node-set
2217 *
2218 * Implements the EXSLT - Sets difference() function:
2219 * node-set set:difference (node-set, node-set)
2220 *
2221 * Returns the difference between the two node sets, or nodes1 if
2222 * nodes2 is empty
2223 */
2224xmlNodeSetPtr
2225xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2226 xmlNodeSetPtr ret;
2227 int i, l1;
2228 xmlNodePtr cur;
2229
2230 if (xmlXPathNodeSetIsEmpty(nodes2))
2231 return(nodes1);
2232
2233 ret = xmlXPathNodeSetCreate(NULL);
2234 if (xmlXPathNodeSetIsEmpty(nodes1))
2235 return(ret);
2236
2237 l1 = xmlXPathNodeSetGetLength(nodes1);
2238
2239 for (i = 0; i < l1; i++) {
2240 cur = xmlXPathNodeSetItem(nodes1, i);
2241 if (!xmlXPathNodeSetContains(nodes2, cur))
2242 xmlXPathNodeSetAddUnique(ret, cur);
2243 }
2244 return(ret);
2245}
2246
2247/**
2248 * xmlXPathIntersection:
2249 * @nodes1: a node-set
2250 * @nodes2: a node-set
2251 *
2252 * Implements the EXSLT - Sets intersection() function:
2253 * node-set set:intersection (node-set, node-set)
2254 *
2255 * Returns a node set comprising the nodes that are within both the
2256 * node sets passed as arguments
2257 */
2258xmlNodeSetPtr
2259xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2260 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2261 int i, l1;
2262 xmlNodePtr cur;
2263
2264 if (xmlXPathNodeSetIsEmpty(nodes1))
2265 return(ret);
2266 if (xmlXPathNodeSetIsEmpty(nodes2))
2267 return(ret);
2268
2269 l1 = xmlXPathNodeSetGetLength(nodes1);
2270
2271 for (i = 0; i < l1; i++) {
2272 cur = xmlXPathNodeSetItem(nodes1, i);
2273 if (xmlXPathNodeSetContains(nodes2, cur))
2274 xmlXPathNodeSetAddUnique(ret, cur);
2275 }
2276 return(ret);
2277}
2278
2279/**
2280 * xmlXPathDistinctSorted:
2281 * @nodes: a node-set, sorted by document order
2282 *
2283 * Implements the EXSLT - Sets distinct() function:
2284 * node-set set:distinct (node-set)
2285 *
2286 * Returns a subset of the nodes contained in @nodes, or @nodes if
2287 * it is empty
2288 */
2289xmlNodeSetPtr
2290xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2291 xmlNodeSetPtr ret;
2292 xmlHashTablePtr hash;
2293 int i, l;
2294 xmlChar * strval;
2295 xmlNodePtr cur;
2296
2297 if (xmlXPathNodeSetIsEmpty(nodes))
2298 return(nodes);
2299
2300 ret = xmlXPathNodeSetCreate(NULL);
2301 l = xmlXPathNodeSetGetLength(nodes);
2302 hash = xmlHashCreate (l);
2303 for (i = 0; i < l; i++) {
2304 cur = xmlXPathNodeSetItem(nodes, i);
2305 strval = xmlXPathCastNodeToString(cur);
2306 if (xmlHashLookup(hash, strval) == NULL) {
2307 xmlHashAddEntry(hash, strval, strval);
2308 xmlXPathNodeSetAddUnique(ret, cur);
2309 } else {
2310 xmlFree(strval);
2311 }
2312 }
2313 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2314 return(ret);
2315}
2316
2317/**
2318 * xmlXPathDistinct:
2319 * @nodes: a node-set
2320 *
2321 * Implements the EXSLT - Sets distinct() function:
2322 * node-set set:distinct (node-set)
2323 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2324 * is called with the sorted node-set
2325 *
2326 * Returns a subset of the nodes contained in @nodes, or @nodes if
2327 * it is empty
2328 */
2329xmlNodeSetPtr
2330xmlXPathDistinct (xmlNodeSetPtr nodes) {
2331 if (xmlXPathNodeSetIsEmpty(nodes))
2332 return(nodes);
2333
2334 xmlXPathNodeSetSort(nodes);
2335 return(xmlXPathDistinctSorted(nodes));
2336}
2337
2338/**
2339 * xmlXPathHasSameNodes:
2340 * @nodes1: a node-set
2341 * @nodes2: a node-set
2342 *
2343 * Implements the EXSLT - Sets has-same-nodes function:
2344 * boolean set:has-same-node(node-set, node-set)
2345 *
2346 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2347 * otherwise
2348 */
2349int
2350xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2351 int i, l;
2352 xmlNodePtr cur;
2353
2354 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2355 xmlXPathNodeSetIsEmpty(nodes2))
2356 return(0);
2357
2358 l = xmlXPathNodeSetGetLength(nodes1);
2359 for (i = 0; i < l; i++) {
2360 cur = xmlXPathNodeSetItem(nodes1, i);
2361 if (xmlXPathNodeSetContains(nodes2, cur))
2362 return(1);
2363 }
2364 return(0);
2365}
2366
2367/**
2368 * xmlXPathNodeLeadingSorted:
2369 * @nodes: a node-set, sorted by document order
2370 * @node: a node
2371 *
2372 * Implements the EXSLT - Sets leading() function:
2373 * node-set set:leading (node-set, node-set)
2374 *
2375 * Returns the nodes in @nodes that precede @node in document order,
2376 * @nodes if @node is NULL or an empty node-set if @nodes
2377 * doesn't contain @node
2378 */
2379xmlNodeSetPtr
2380xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2381 int i, l;
2382 xmlNodePtr cur;
2383 xmlNodeSetPtr ret;
2384
2385 if (node == NULL)
2386 return(nodes);
2387
2388 ret = xmlXPathNodeSetCreate(NULL);
2389 if (xmlXPathNodeSetIsEmpty(nodes) ||
2390 (!xmlXPathNodeSetContains(nodes, node)))
2391 return(ret);
2392
2393 l = xmlXPathNodeSetGetLength(nodes);
2394 for (i = 0; i < l; i++) {
2395 cur = xmlXPathNodeSetItem(nodes, i);
2396 if (cur == node)
2397 break;
2398 xmlXPathNodeSetAddUnique(ret, cur);
2399 }
2400 return(ret);
2401}
2402
2403/**
2404 * xmlXPathNodeLeading:
2405 * @nodes: a node-set
2406 * @node: a node
2407 *
2408 * Implements the EXSLT - Sets leading() function:
2409 * node-set set:leading (node-set, node-set)
2410 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2411 * is called.
2412 *
2413 * Returns the nodes in @nodes that precede @node in document order,
2414 * @nodes if @node is NULL or an empty node-set if @nodes
2415 * doesn't contain @node
2416 */
2417xmlNodeSetPtr
2418xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2419 xmlXPathNodeSetSort(nodes);
2420 return(xmlXPathNodeLeadingSorted(nodes, node));
2421}
2422
2423/**
2424 * xmlXPathLeadingSorted:
2425 * @nodes1: a node-set, sorted by document order
2426 * @nodes2: a node-set, sorted by document order
2427 *
2428 * Implements the EXSLT - Sets leading() function:
2429 * node-set set:leading (node-set, node-set)
2430 *
2431 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2432 * in document order, @nodes1 if @nodes2 is NULL or empty or
2433 * an empty node-set if @nodes1 doesn't contain @nodes2
2434 */
2435xmlNodeSetPtr
2436xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2437 if (xmlXPathNodeSetIsEmpty(nodes2))
2438 return(nodes1);
2439 return(xmlXPathNodeLeadingSorted(nodes1,
2440 xmlXPathNodeSetItem(nodes2, 1)));
2441}
2442
2443/**
2444 * xmlXPathLeading:
2445 * @nodes1: a node-set
2446 * @nodes2: a node-set
2447 *
2448 * Implements the EXSLT - Sets leading() function:
2449 * node-set set:leading (node-set, node-set)
2450 * @nodes1 and @nodes2 are sorted by document order, then
2451 * #exslSetsLeadingSorted is called.
2452 *
2453 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2454 * in document order, @nodes1 if @nodes2 is NULL or empty or
2455 * an empty node-set if @nodes1 doesn't contain @nodes2
2456 */
2457xmlNodeSetPtr
2458xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2459 if (xmlXPathNodeSetIsEmpty(nodes2))
2460 return(nodes1);
2461 if (xmlXPathNodeSetIsEmpty(nodes1))
2462 return(xmlXPathNodeSetCreate(NULL));
2463 xmlXPathNodeSetSort(nodes1);
2464 xmlXPathNodeSetSort(nodes2);
2465 return(xmlXPathNodeLeadingSorted(nodes1,
2466 xmlXPathNodeSetItem(nodes2, 1)));
2467}
2468
2469/**
2470 * xmlXPathNodeTrailingSorted:
2471 * @nodes: a node-set, sorted by document order
2472 * @node: a node
2473 *
2474 * Implements the EXSLT - Sets trailing() function:
2475 * node-set set:trailing (node-set, node-set)
2476 *
2477 * Returns the nodes in @nodes that follow @node in document order,
2478 * @nodes if @node is NULL or an empty node-set if @nodes
2479 * doesn't contain @node
2480 */
2481xmlNodeSetPtr
2482xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2483 int i, l;
2484 xmlNodePtr cur;
2485 xmlNodeSetPtr ret;
2486
2487 if (node == NULL)
2488 return(nodes);
2489
2490 ret = xmlXPathNodeSetCreate(NULL);
2491 if (xmlXPathNodeSetIsEmpty(nodes) ||
2492 (!xmlXPathNodeSetContains(nodes, node)))
2493 return(ret);
2494
2495 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002496 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002497 cur = xmlXPathNodeSetItem(nodes, i);
2498 if (cur == node)
2499 break;
2500 xmlXPathNodeSetAddUnique(ret, cur);
2501 }
2502 return(ret);
2503}
2504
2505/**
2506 * xmlXPathNodeTrailing:
2507 * @nodes: a node-set
2508 * @node: a node
2509 *
2510 * Implements the EXSLT - Sets trailing() function:
2511 * node-set set:trailing (node-set, node-set)
2512 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2513 * is called.
2514 *
2515 * Returns the nodes in @nodes that follow @node in document order,
2516 * @nodes if @node is NULL or an empty node-set if @nodes
2517 * doesn't contain @node
2518 */
2519xmlNodeSetPtr
2520xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2521 xmlXPathNodeSetSort(nodes);
2522 return(xmlXPathNodeTrailingSorted(nodes, node));
2523}
2524
2525/**
2526 * xmlXPathTrailingSorted:
2527 * @nodes1: a node-set, sorted by document order
2528 * @nodes2: a node-set, sorted by document order
2529 *
2530 * Implements the EXSLT - Sets trailing() function:
2531 * node-set set:trailing (node-set, node-set)
2532 *
2533 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2534 * in document order, @nodes1 if @nodes2 is NULL or empty or
2535 * an empty node-set if @nodes1 doesn't contain @nodes2
2536 */
2537xmlNodeSetPtr
2538xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2539 if (xmlXPathNodeSetIsEmpty(nodes2))
2540 return(nodes1);
2541 return(xmlXPathNodeTrailingSorted(nodes1,
2542 xmlXPathNodeSetItem(nodes2, 0)));
2543}
2544
2545/**
2546 * xmlXPathTrailing:
2547 * @nodes1: a node-set
2548 * @nodes2: a node-set
2549 *
2550 * Implements the EXSLT - Sets trailing() function:
2551 * node-set set:trailing (node-set, node-set)
2552 * @nodes1 and @nodes2 are sorted by document order, then
2553 * #xmlXPathTrailingSorted is called.
2554 *
2555 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2556 * in document order, @nodes1 if @nodes2 is NULL or empty or
2557 * an empty node-set if @nodes1 doesn't contain @nodes2
2558 */
2559xmlNodeSetPtr
2560xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2561 if (xmlXPathNodeSetIsEmpty(nodes2))
2562 return(nodes1);
2563 if (xmlXPathNodeSetIsEmpty(nodes1))
2564 return(xmlXPathNodeSetCreate(NULL));
2565 xmlXPathNodeSetSort(nodes1);
2566 xmlXPathNodeSetSort(nodes2);
2567 return(xmlXPathNodeTrailingSorted(nodes1,
2568 xmlXPathNodeSetItem(nodes2, 0)));
2569}
2570
Owen Taylor3473f882001-02-23 17:55:21 +00002571/************************************************************************
2572 * *
2573 * Routines to handle extra functions *
2574 * *
2575 ************************************************************************/
2576
2577/**
2578 * xmlXPathRegisterFunc:
2579 * @ctxt: the XPath context
2580 * @name: the function name
2581 * @f: the function implementation or NULL
2582 *
2583 * Register a new function. If @f is NULL it unregisters the function
2584 *
2585 * Returns 0 in case of success, -1 in case of error
2586 */
2587int
2588xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2589 xmlXPathFunction f) {
2590 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2591}
2592
2593/**
2594 * xmlXPathRegisterFuncNS:
2595 * @ctxt: the XPath context
2596 * @name: the function name
2597 * @ns_uri: the function namespace URI
2598 * @f: the function implementation or NULL
2599 *
2600 * Register a new function. If @f is NULL it unregisters the function
2601 *
2602 * Returns 0 in case of success, -1 in case of error
2603 */
2604int
2605xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2606 const xmlChar *ns_uri, xmlXPathFunction f) {
2607 if (ctxt == NULL)
2608 return(-1);
2609 if (name == NULL)
2610 return(-1);
2611
2612 if (ctxt->funcHash == NULL)
2613 ctxt->funcHash = xmlHashCreate(0);
2614 if (ctxt->funcHash == NULL)
2615 return(-1);
2616 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2617}
2618
2619/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002620 * xmlXPathRegisterFuncLookup:
2621 * @ctxt: the XPath context
2622 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002623 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00002624 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002625 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00002626 */
2627void
2628xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2629 xmlXPathFuncLookupFunc f,
2630 void *funcCtxt) {
2631 if (ctxt == NULL)
2632 return;
2633 ctxt->funcLookupFunc = (void *) f;
2634 ctxt->funcLookupData = funcCtxt;
2635}
2636
2637/**
Owen Taylor3473f882001-02-23 17:55:21 +00002638 * xmlXPathFunctionLookup:
2639 * @ctxt: the XPath context
2640 * @name: the function name
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
2648xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002649 if (ctxt == NULL)
2650 return (NULL);
2651
2652 if (ctxt->funcLookupFunc != NULL) {
2653 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002654 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002655
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002656 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002657 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002658 if (ret != NULL)
2659 return(ret);
2660 }
Owen Taylor3473f882001-02-23 17:55:21 +00002661 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2662}
2663
2664/**
2665 * xmlXPathFunctionLookupNS:
2666 * @ctxt: the XPath context
2667 * @name: the function name
2668 * @ns_uri: the function namespace URI
2669 *
2670 * Search in the Function array of the context for the given
2671 * function.
2672 *
2673 * Returns the xmlXPathFunction or NULL if not found
2674 */
2675xmlXPathFunction
2676xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2677 const xmlChar *ns_uri) {
2678 if (ctxt == NULL)
2679 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002680 if (name == NULL)
2681 return(NULL);
2682
Thomas Broyerba4ad322001-07-26 16:55:21 +00002683 if (ctxt->funcLookupFunc != NULL) {
2684 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002685 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002686
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002687 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002688 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002689 if (ret != NULL)
2690 return(ret);
2691 }
2692
2693 if (ctxt->funcHash == NULL)
2694 return(NULL);
2695
Owen Taylor3473f882001-02-23 17:55:21 +00002696 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2697}
2698
2699/**
2700 * xmlXPathRegisteredFuncsCleanup:
2701 * @ctxt: the XPath context
2702 *
2703 * Cleanup the XPath context data associated to registered functions
2704 */
2705void
2706xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2707 if (ctxt == NULL)
2708 return;
2709
2710 xmlHashFree(ctxt->funcHash, NULL);
2711 ctxt->funcHash = NULL;
2712}
2713
2714/************************************************************************
2715 * *
2716 * Routines to handle Variable *
2717 * *
2718 ************************************************************************/
2719
2720/**
2721 * xmlXPathRegisterVariable:
2722 * @ctxt: the XPath context
2723 * @name: the variable name
2724 * @value: the variable value or NULL
2725 *
2726 * Register a new variable value. If @value is NULL it unregisters
2727 * the variable
2728 *
2729 * Returns 0 in case of success, -1 in case of error
2730 */
2731int
2732xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2733 xmlXPathObjectPtr value) {
2734 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2735}
2736
2737/**
2738 * xmlXPathRegisterVariableNS:
2739 * @ctxt: the XPath context
2740 * @name: the variable name
2741 * @ns_uri: the variable namespace URI
2742 * @value: the variable value or NULL
2743 *
2744 * Register a new variable value. If @value is NULL it unregisters
2745 * the variable
2746 *
2747 * Returns 0 in case of success, -1 in case of error
2748 */
2749int
2750xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2751 const xmlChar *ns_uri,
2752 xmlXPathObjectPtr value) {
2753 if (ctxt == NULL)
2754 return(-1);
2755 if (name == NULL)
2756 return(-1);
2757
2758 if (ctxt->varHash == NULL)
2759 ctxt->varHash = xmlHashCreate(0);
2760 if (ctxt->varHash == NULL)
2761 return(-1);
2762 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2763 (void *) value,
2764 (xmlHashDeallocator)xmlXPathFreeObject));
2765}
2766
2767/**
2768 * xmlXPathRegisterVariableLookup:
2769 * @ctxt: the XPath context
2770 * @f: the lookup function
2771 * @data: the lookup data
2772 *
2773 * register an external mechanism to do variable lookup
2774 */
2775void
2776xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2777 xmlXPathVariableLookupFunc f, void *data) {
2778 if (ctxt == NULL)
2779 return;
2780 ctxt->varLookupFunc = (void *) f;
2781 ctxt->varLookupData = data;
2782}
2783
2784/**
2785 * xmlXPathVariableLookup:
2786 * @ctxt: the XPath context
2787 * @name: the variable name
2788 *
2789 * Search in the Variable array of the context for the given
2790 * variable value.
2791 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002792 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002793 */
2794xmlXPathObjectPtr
2795xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2796 if (ctxt == NULL)
2797 return(NULL);
2798
2799 if (ctxt->varLookupFunc != NULL) {
2800 xmlXPathObjectPtr ret;
2801
2802 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2803 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00002804 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002805 }
2806 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
2807}
2808
2809/**
2810 * xmlXPathVariableLookupNS:
2811 * @ctxt: the XPath context
2812 * @name: the variable name
2813 * @ns_uri: the variable namespace URI
2814 *
2815 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00002816 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00002817 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002818 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002819 */
2820xmlXPathObjectPtr
2821xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2822 const xmlChar *ns_uri) {
2823 if (ctxt == NULL)
2824 return(NULL);
2825
2826 if (ctxt->varLookupFunc != NULL) {
2827 xmlXPathObjectPtr ret;
2828
2829 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2830 (ctxt->varLookupData, name, ns_uri);
2831 if (ret != NULL) return(ret);
2832 }
2833
2834 if (ctxt->varHash == NULL)
2835 return(NULL);
2836 if (name == NULL)
2837 return(NULL);
2838
Daniel Veillard8c357d52001-07-03 23:43:33 +00002839 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
2840 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00002841}
2842
2843/**
2844 * xmlXPathRegisteredVariablesCleanup:
2845 * @ctxt: the XPath context
2846 *
2847 * Cleanup the XPath context data associated to registered variables
2848 */
2849void
2850xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
2851 if (ctxt == NULL)
2852 return;
2853
Daniel Veillard76d66f42001-05-16 21:05:17 +00002854 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00002855 ctxt->varHash = NULL;
2856}
2857
2858/**
2859 * xmlXPathRegisterNs:
2860 * @ctxt: the XPath context
2861 * @prefix: the namespace prefix
2862 * @ns_uri: the namespace name
2863 *
2864 * Register a new namespace. If @ns_uri is NULL it unregisters
2865 * the namespace
2866 *
2867 * Returns 0 in case of success, -1 in case of error
2868 */
2869int
2870xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
2871 const xmlChar *ns_uri) {
2872 if (ctxt == NULL)
2873 return(-1);
2874 if (prefix == NULL)
2875 return(-1);
2876
2877 if (ctxt->nsHash == NULL)
2878 ctxt->nsHash = xmlHashCreate(10);
2879 if (ctxt->nsHash == NULL)
2880 return(-1);
Daniel Veillard42766c02002-08-22 20:52:17 +00002881 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00002882 (xmlHashDeallocator)xmlFree));
2883}
2884
2885/**
2886 * xmlXPathNsLookup:
2887 * @ctxt: the XPath context
2888 * @prefix: the namespace prefix value
2889 *
2890 * Search in the namespace declaration array of the context for the given
2891 * namespace name associated to the given prefix
2892 *
2893 * Returns the value or NULL if not found
2894 */
2895const xmlChar *
2896xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
2897 if (ctxt == NULL)
2898 return(NULL);
2899 if (prefix == NULL)
2900 return(NULL);
2901
2902#ifdef XML_XML_NAMESPACE
2903 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
2904 return(XML_XML_NAMESPACE);
2905#endif
2906
Daniel Veillardc8f620b2001-04-30 20:31:33 +00002907 if (ctxt->namespaces != NULL) {
2908 int i;
2909
2910 for (i = 0;i < ctxt->nsNr;i++) {
2911 if ((ctxt->namespaces[i] != NULL) &&
2912 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
2913 return(ctxt->namespaces[i]->href);
2914 }
2915 }
Owen Taylor3473f882001-02-23 17:55:21 +00002916
2917 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
2918}
2919
2920/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002921 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00002922 * @ctxt: the XPath context
2923 *
2924 * Cleanup the XPath context data associated to registered variables
2925 */
2926void
2927xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
2928 if (ctxt == NULL)
2929 return;
2930
Daniel Veillard42766c02002-08-22 20:52:17 +00002931 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00002932 ctxt->nsHash = NULL;
2933}
2934
2935/************************************************************************
2936 * *
2937 * Routines to handle Values *
2938 * *
2939 ************************************************************************/
2940
2941/* Allocations are terrible, one need to optimize all this !!! */
2942
2943/**
2944 * xmlXPathNewFloat:
2945 * @val: the double value
2946 *
2947 * Create a new xmlXPathObjectPtr of type double and of value @val
2948 *
2949 * Returns the newly created object.
2950 */
2951xmlXPathObjectPtr
2952xmlXPathNewFloat(double val) {
2953 xmlXPathObjectPtr ret;
2954
2955 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2956 if (ret == NULL) {
2957 xmlGenericError(xmlGenericErrorContext,
2958 "xmlXPathNewFloat: out of memory\n");
2959 return(NULL);
2960 }
2961 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2962 ret->type = XPATH_NUMBER;
2963 ret->floatval = val;
2964 return(ret);
2965}
2966
2967/**
2968 * xmlXPathNewBoolean:
2969 * @val: the boolean value
2970 *
2971 * Create a new xmlXPathObjectPtr of type boolean and of value @val
2972 *
2973 * Returns the newly created object.
2974 */
2975xmlXPathObjectPtr
2976xmlXPathNewBoolean(int val) {
2977 xmlXPathObjectPtr ret;
2978
2979 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2980 if (ret == NULL) {
2981 xmlGenericError(xmlGenericErrorContext,
2982 "xmlXPathNewBoolean: out of memory\n");
2983 return(NULL);
2984 }
2985 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2986 ret->type = XPATH_BOOLEAN;
2987 ret->boolval = (val != 0);
2988 return(ret);
2989}
2990
2991/**
2992 * xmlXPathNewString:
2993 * @val: the xmlChar * value
2994 *
2995 * Create a new xmlXPathObjectPtr of type string and of value @val
2996 *
2997 * Returns the newly created object.
2998 */
2999xmlXPathObjectPtr
3000xmlXPathNewString(const xmlChar *val) {
3001 xmlXPathObjectPtr ret;
3002
3003 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3004 if (ret == NULL) {
3005 xmlGenericError(xmlGenericErrorContext,
3006 "xmlXPathNewString: out of memory\n");
3007 return(NULL);
3008 }
3009 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3010 ret->type = XPATH_STRING;
3011 if (val != NULL)
3012 ret->stringval = xmlStrdup(val);
3013 else
3014 ret->stringval = xmlStrdup((const xmlChar *)"");
3015 return(ret);
3016}
3017
3018/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003019 * xmlXPathWrapString:
3020 * @val: the xmlChar * value
3021 *
3022 * Wraps the @val string into an XPath object.
3023 *
3024 * Returns the newly created object.
3025 */
3026xmlXPathObjectPtr
3027xmlXPathWrapString (xmlChar *val) {
3028 xmlXPathObjectPtr ret;
3029
3030 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3031 if (ret == NULL) {
3032 xmlGenericError(xmlGenericErrorContext,
3033 "xmlXPathWrapString: out of memory\n");
3034 return(NULL);
3035 }
3036 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3037 ret->type = XPATH_STRING;
3038 ret->stringval = val;
3039 return(ret);
3040}
3041
3042/**
Owen Taylor3473f882001-02-23 17:55:21 +00003043 * xmlXPathNewCString:
3044 * @val: the char * value
3045 *
3046 * Create a new xmlXPathObjectPtr of type string and of value @val
3047 *
3048 * Returns the newly created object.
3049 */
3050xmlXPathObjectPtr
3051xmlXPathNewCString(const char *val) {
3052 xmlXPathObjectPtr ret;
3053
3054 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3055 if (ret == NULL) {
3056 xmlGenericError(xmlGenericErrorContext,
3057 "xmlXPathNewCString: out of memory\n");
3058 return(NULL);
3059 }
3060 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3061 ret->type = XPATH_STRING;
3062 ret->stringval = xmlStrdup(BAD_CAST val);
3063 return(ret);
3064}
3065
3066/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003067 * xmlXPathWrapCString:
3068 * @val: the char * value
3069 *
3070 * Wraps a string into an XPath object.
3071 *
3072 * Returns the newly created object.
3073 */
3074xmlXPathObjectPtr
3075xmlXPathWrapCString (char * val) {
3076 return(xmlXPathWrapString((xmlChar *)(val)));
3077}
3078
3079/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003080 * xmlXPathWrapExternal:
3081 * @val: the user data
3082 *
3083 * Wraps the @val data into an XPath object.
3084 *
3085 * Returns the newly created object.
3086 */
3087xmlXPathObjectPtr
3088xmlXPathWrapExternal (void *val) {
3089 xmlXPathObjectPtr ret;
3090
3091 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3092 if (ret == NULL) {
3093 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003094 "xmlXPathWrapExternal: out of memory\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003095 return(NULL);
3096 }
3097 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3098 ret->type = XPATH_USERS;
3099 ret->user = val;
3100 return(ret);
3101}
3102
3103/**
Owen Taylor3473f882001-02-23 17:55:21 +00003104 * xmlXPathObjectCopy:
3105 * @val: the original object
3106 *
3107 * allocate a new copy of a given object
3108 *
3109 * Returns the newly created object.
3110 */
3111xmlXPathObjectPtr
3112xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3113 xmlXPathObjectPtr ret;
3114
3115 if (val == NULL)
3116 return(NULL);
3117
3118 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3119 if (ret == NULL) {
3120 xmlGenericError(xmlGenericErrorContext,
3121 "xmlXPathObjectCopy: out of memory\n");
3122 return(NULL);
3123 }
3124 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3125 switch (val->type) {
3126 case XPATH_BOOLEAN:
3127 case XPATH_NUMBER:
3128 case XPATH_POINT:
3129 case XPATH_RANGE:
3130 break;
3131 case XPATH_STRING:
3132 ret->stringval = xmlStrdup(val->stringval);
3133 break;
3134 case XPATH_XSLT_TREE:
3135 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003136 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillardef0b4502003-03-24 13:57:34 +00003137 xmlNodePtr cur, top, tmp;
3138
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003139 ret->boolval = 1;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003140 top = xmlCopyNode(val->nodesetval->nodeTab[0], 0);
3141 ret->user = top;
3142 if (top != NULL) {
3143 top->doc = (xmlDocPtr) top;
3144 cur = val->nodesetval->nodeTab[0]->children;
3145 while (cur != NULL) {
3146 tmp = xmlDocCopyNode(cur, (xmlDocPtr) top, 1);
3147 xmlAddChild(top, tmp);
3148 cur = cur->next;
3149 }
3150 }
3151 ret->nodesetval = xmlXPathNodeSetCreate(top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003152 } else
Owen Taylor3473f882001-02-23 17:55:21 +00003153 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003154 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00003155 break;
3156 case XPATH_NODESET:
3157 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003158 /* Do not deallocate the copied tree value */
3159 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003160 break;
3161 case XPATH_LOCATIONSET:
3162#ifdef LIBXML_XPTR_ENABLED
3163 {
3164 xmlLocationSetPtr loc = val->user;
3165 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3166 break;
3167 }
3168#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00003169 case XPATH_USERS:
3170 ret->user = val->user;
3171 break;
3172 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00003173 xmlGenericError(xmlGenericErrorContext,
3174 "xmlXPathObjectCopy: unsupported type %d\n",
3175 val->type);
3176 break;
3177 }
3178 return(ret);
3179}
3180
3181/**
3182 * xmlXPathFreeObject:
3183 * @obj: the object to free
3184 *
3185 * Free up an xmlXPathObjectPtr object.
3186 */
3187void
3188xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3189 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003190 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00003191 if (obj->boolval) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003192 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003193 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00003194 xmlFreeNodeList((xmlNodePtr) obj->user);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003195 } else if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00003196 xmlXPathFreeValueTree(obj->nodesetval);
3197 } else {
3198 if (obj->nodesetval != NULL)
3199 xmlXPathFreeNodeSet(obj->nodesetval);
3200 }
Owen Taylor3473f882001-02-23 17:55:21 +00003201#ifdef LIBXML_XPTR_ENABLED
3202 } else if (obj->type == XPATH_LOCATIONSET) {
3203 if (obj->user != NULL)
3204 xmlXPtrFreeLocationSet(obj->user);
3205#endif
3206 } else if (obj->type == XPATH_STRING) {
3207 if (obj->stringval != NULL)
3208 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00003209 }
3210
Owen Taylor3473f882001-02-23 17:55:21 +00003211 xmlFree(obj);
3212}
3213
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003214
3215/************************************************************************
3216 * *
3217 * Type Casting Routines *
3218 * *
3219 ************************************************************************/
3220
3221/**
3222 * xmlXPathCastBooleanToString:
3223 * @val: a boolean
3224 *
3225 * Converts a boolean to its string value.
3226 *
3227 * Returns a newly allocated string.
3228 */
3229xmlChar *
3230xmlXPathCastBooleanToString (int val) {
3231 xmlChar *ret;
3232 if (val)
3233 ret = xmlStrdup((const xmlChar *) "true");
3234 else
3235 ret = xmlStrdup((const xmlChar *) "false");
3236 return(ret);
3237}
3238
3239/**
3240 * xmlXPathCastNumberToString:
3241 * @val: a number
3242 *
3243 * Converts a number to its string value.
3244 *
3245 * Returns a newly allocated string.
3246 */
3247xmlChar *
3248xmlXPathCastNumberToString (double val) {
3249 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00003250 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003251 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003252 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003253 break;
3254 case -1:
3255 ret = xmlStrdup((const xmlChar *) "-Infinity");
3256 break;
3257 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003258 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003259 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00003260 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
3261 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003262 } else {
3263 /* could be improved */
3264 char buf[100];
3265 xmlXPathFormatNumber(val, buf, 100);
3266 ret = xmlStrdup((const xmlChar *) buf);
3267 }
3268 }
3269 return(ret);
3270}
3271
3272/**
3273 * xmlXPathCastNodeToString:
3274 * @node: a node
3275 *
3276 * Converts a node to its string value.
3277 *
3278 * Returns a newly allocated string.
3279 */
3280xmlChar *
3281xmlXPathCastNodeToString (xmlNodePtr node) {
Daniel Veillard23b1f372002-04-18 15:50:05 +00003282 if ((node != NULL) && (node->type == XML_DOCUMENT_NODE))
3283 node = xmlDocGetRootElement((xmlDocPtr) node);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003284 return(xmlNodeGetContent(node));
3285}
3286
3287/**
3288 * xmlXPathCastNodeSetToString:
3289 * @ns: a node-set
3290 *
3291 * Converts a node-set to its string value.
3292 *
3293 * Returns a newly allocated string.
3294 */
3295xmlChar *
3296xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3297 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3298 return(xmlStrdup((const xmlChar *) ""));
3299
3300 xmlXPathNodeSetSort(ns);
3301 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3302}
3303
3304/**
3305 * xmlXPathCastToString:
3306 * @val: an XPath object
3307 *
3308 * Converts an existing object to its string() equivalent
3309 *
3310 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003311 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003312 * string object).
3313 */
3314xmlChar *
3315xmlXPathCastToString(xmlXPathObjectPtr val) {
3316 xmlChar *ret = NULL;
3317
3318 if (val == NULL)
3319 return(xmlStrdup((const xmlChar *) ""));
3320 switch (val->type) {
3321 case XPATH_UNDEFINED:
3322#ifdef DEBUG_EXPR
3323 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3324#endif
3325 ret = xmlStrdup((const xmlChar *) "");
3326 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003327 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003328 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003329 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3330 break;
3331 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00003332 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003333 case XPATH_BOOLEAN:
3334 ret = xmlXPathCastBooleanToString(val->boolval);
3335 break;
3336 case XPATH_NUMBER: {
3337 ret = xmlXPathCastNumberToString(val->floatval);
3338 break;
3339 }
3340 case XPATH_USERS:
3341 case XPATH_POINT:
3342 case XPATH_RANGE:
3343 case XPATH_LOCATIONSET:
3344 TODO
3345 ret = xmlStrdup((const xmlChar *) "");
3346 break;
3347 }
3348 return(ret);
3349}
3350
3351/**
3352 * xmlXPathConvertString:
3353 * @val: an XPath object
3354 *
3355 * Converts an existing object to its string() equivalent
3356 *
3357 * Returns the new object, the old one is freed (or the operation
3358 * is done directly on @val)
3359 */
3360xmlXPathObjectPtr
3361xmlXPathConvertString(xmlXPathObjectPtr val) {
3362 xmlChar *res = NULL;
3363
3364 if (val == NULL)
3365 return(xmlXPathNewCString(""));
3366
3367 switch (val->type) {
3368 case XPATH_UNDEFINED:
3369#ifdef DEBUG_EXPR
3370 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3371#endif
3372 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003373 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003374 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003375 res = xmlXPathCastNodeSetToString(val->nodesetval);
3376 break;
3377 case XPATH_STRING:
3378 return(val);
3379 case XPATH_BOOLEAN:
3380 res = xmlXPathCastBooleanToString(val->boolval);
3381 break;
3382 case XPATH_NUMBER:
3383 res = xmlXPathCastNumberToString(val->floatval);
3384 break;
3385 case XPATH_USERS:
3386 case XPATH_POINT:
3387 case XPATH_RANGE:
3388 case XPATH_LOCATIONSET:
3389 TODO;
3390 break;
3391 }
3392 xmlXPathFreeObject(val);
3393 if (res == NULL)
3394 return(xmlXPathNewCString(""));
3395 return(xmlXPathWrapString(res));
3396}
3397
3398/**
3399 * xmlXPathCastBooleanToNumber:
3400 * @val: a boolean
3401 *
3402 * Converts a boolean to its number value
3403 *
3404 * Returns the number value
3405 */
3406double
3407xmlXPathCastBooleanToNumber(int val) {
3408 if (val)
3409 return(1.0);
3410 return(0.0);
3411}
3412
3413/**
3414 * xmlXPathCastStringToNumber:
3415 * @val: a string
3416 *
3417 * Converts a string to its number value
3418 *
3419 * Returns the number value
3420 */
3421double
3422xmlXPathCastStringToNumber(const xmlChar * val) {
3423 return(xmlXPathStringEvalNumber(val));
3424}
3425
3426/**
3427 * xmlXPathCastNodeToNumber:
3428 * @node: a node
3429 *
3430 * Converts a node to its number value
3431 *
3432 * Returns the number value
3433 */
3434double
3435xmlXPathCastNodeToNumber (xmlNodePtr node) {
3436 xmlChar *strval;
3437 double ret;
3438
3439 if (node == NULL)
3440 return(xmlXPathNAN);
3441 strval = xmlXPathCastNodeToString(node);
3442 if (strval == NULL)
3443 return(xmlXPathNAN);
3444 ret = xmlXPathCastStringToNumber(strval);
3445 xmlFree(strval);
3446
3447 return(ret);
3448}
3449
3450/**
3451 * xmlXPathCastNodeSetToNumber:
3452 * @ns: a node-set
3453 *
3454 * Converts a node-set to its number value
3455 *
3456 * Returns the number value
3457 */
3458double
3459xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3460 xmlChar *str;
3461 double ret;
3462
3463 if (ns == NULL)
3464 return(xmlXPathNAN);
3465 str = xmlXPathCastNodeSetToString(ns);
3466 ret = xmlXPathCastStringToNumber(str);
3467 xmlFree(str);
3468 return(ret);
3469}
3470
3471/**
3472 * xmlXPathCastToNumber:
3473 * @val: an XPath object
3474 *
3475 * Converts an XPath object to its number value
3476 *
3477 * Returns the number value
3478 */
3479double
3480xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3481 double ret = 0.0;
3482
3483 if (val == NULL)
3484 return(xmlXPathNAN);
3485 switch (val->type) {
3486 case XPATH_UNDEFINED:
3487#ifdef DEGUB_EXPR
3488 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3489#endif
3490 ret = xmlXPathNAN;
3491 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003492 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003493 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003494 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3495 break;
3496 case XPATH_STRING:
3497 ret = xmlXPathCastStringToNumber(val->stringval);
3498 break;
3499 case XPATH_NUMBER:
3500 ret = val->floatval;
3501 break;
3502 case XPATH_BOOLEAN:
3503 ret = xmlXPathCastBooleanToNumber(val->boolval);
3504 break;
3505 case XPATH_USERS:
3506 case XPATH_POINT:
3507 case XPATH_RANGE:
3508 case XPATH_LOCATIONSET:
3509 TODO;
3510 ret = xmlXPathNAN;
3511 break;
3512 }
3513 return(ret);
3514}
3515
3516/**
3517 * xmlXPathConvertNumber:
3518 * @val: an XPath object
3519 *
3520 * Converts an existing object to its number() equivalent
3521 *
3522 * Returns the new object, the old one is freed (or the operation
3523 * is done directly on @val)
3524 */
3525xmlXPathObjectPtr
3526xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3527 xmlXPathObjectPtr ret;
3528
3529 if (val == NULL)
3530 return(xmlXPathNewFloat(0.0));
3531 if (val->type == XPATH_NUMBER)
3532 return(val);
3533 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3534 xmlXPathFreeObject(val);
3535 return(ret);
3536}
3537
3538/**
3539 * xmlXPathCastNumberToBoolean:
3540 * @val: a number
3541 *
3542 * Converts a number to its boolean value
3543 *
3544 * Returns the boolean value
3545 */
3546int
3547xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003548 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003549 return(0);
3550 return(1);
3551}
3552
3553/**
3554 * xmlXPathCastStringToBoolean:
3555 * @val: a string
3556 *
3557 * Converts a string to its boolean value
3558 *
3559 * Returns the boolean value
3560 */
3561int
3562xmlXPathCastStringToBoolean (const xmlChar *val) {
3563 if ((val == NULL) || (xmlStrlen(val) == 0))
3564 return(0);
3565 return(1);
3566}
3567
3568/**
3569 * xmlXPathCastNodeSetToBoolean:
3570 * @ns: a node-set
3571 *
3572 * Converts a node-set to its boolean value
3573 *
3574 * Returns the boolean value
3575 */
3576int
3577xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3578 if ((ns == NULL) || (ns->nodeNr == 0))
3579 return(0);
3580 return(1);
3581}
3582
3583/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003584 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003585 * @val: an XPath object
3586 *
3587 * Converts an XPath object to its boolean value
3588 *
3589 * Returns the boolean value
3590 */
3591int
3592xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3593 int ret = 0;
3594
3595 if (val == NULL)
3596 return(0);
3597 switch (val->type) {
3598 case XPATH_UNDEFINED:
3599#ifdef DEBUG_EXPR
3600 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3601#endif
3602 ret = 0;
3603 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003604 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003605 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003606 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3607 break;
3608 case XPATH_STRING:
3609 ret = xmlXPathCastStringToBoolean(val->stringval);
3610 break;
3611 case XPATH_NUMBER:
3612 ret = xmlXPathCastNumberToBoolean(val->floatval);
3613 break;
3614 case XPATH_BOOLEAN:
3615 ret = val->boolval;
3616 break;
3617 case XPATH_USERS:
3618 case XPATH_POINT:
3619 case XPATH_RANGE:
3620 case XPATH_LOCATIONSET:
3621 TODO;
3622 ret = 0;
3623 break;
3624 }
3625 return(ret);
3626}
3627
3628
3629/**
3630 * xmlXPathConvertBoolean:
3631 * @val: an XPath object
3632 *
3633 * Converts an existing object to its boolean() equivalent
3634 *
3635 * Returns the new object, the old one is freed (or the operation
3636 * is done directly on @val)
3637 */
3638xmlXPathObjectPtr
3639xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3640 xmlXPathObjectPtr ret;
3641
3642 if (val == NULL)
3643 return(xmlXPathNewBoolean(0));
3644 if (val->type == XPATH_BOOLEAN)
3645 return(val);
3646 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3647 xmlXPathFreeObject(val);
3648 return(ret);
3649}
3650
Owen Taylor3473f882001-02-23 17:55:21 +00003651/************************************************************************
3652 * *
3653 * Routines to handle XPath contexts *
3654 * *
3655 ************************************************************************/
3656
3657/**
3658 * xmlXPathNewContext:
3659 * @doc: the XML document
3660 *
3661 * Create a new xmlXPathContext
3662 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00003663 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00003664 */
3665xmlXPathContextPtr
3666xmlXPathNewContext(xmlDocPtr doc) {
3667 xmlXPathContextPtr ret;
3668
3669 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3670 if (ret == NULL) {
3671 xmlGenericError(xmlGenericErrorContext,
3672 "xmlXPathNewContext: out of memory\n");
3673 return(NULL);
3674 }
3675 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3676 ret->doc = doc;
3677 ret->node = NULL;
3678
3679 ret->varHash = NULL;
3680
3681 ret->nb_types = 0;
3682 ret->max_types = 0;
3683 ret->types = NULL;
3684
3685 ret->funcHash = xmlHashCreate(0);
3686
3687 ret->nb_axis = 0;
3688 ret->max_axis = 0;
3689 ret->axis = NULL;
3690
3691 ret->nsHash = NULL;
3692 ret->user = NULL;
3693
3694 ret->contextSize = -1;
3695 ret->proximityPosition = -1;
3696
3697 xmlXPathRegisterAllFunctions(ret);
3698
3699 return(ret);
3700}
3701
3702/**
3703 * xmlXPathFreeContext:
3704 * @ctxt: the context to free
3705 *
3706 * Free up an xmlXPathContext
3707 */
3708void
3709xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3710 xmlXPathRegisteredNsCleanup(ctxt);
3711 xmlXPathRegisteredFuncsCleanup(ctxt);
3712 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003713 xmlFree(ctxt);
3714}
3715
3716/************************************************************************
3717 * *
3718 * Routines to handle XPath parser contexts *
3719 * *
3720 ************************************************************************/
3721
3722#define CHECK_CTXT(ctxt) \
3723 if (ctxt == NULL) { \
3724 xmlGenericError(xmlGenericErrorContext, \
3725 "%s:%d Internal error: ctxt == NULL\n", \
3726 __FILE__, __LINE__); \
3727 } \
3728
3729
3730#define CHECK_CONTEXT(ctxt) \
3731 if (ctxt == NULL) { \
3732 xmlGenericError(xmlGenericErrorContext, \
3733 "%s:%d Internal error: no context\n", \
3734 __FILE__, __LINE__); \
3735 } \
3736 else if (ctxt->doc == NULL) { \
3737 xmlGenericError(xmlGenericErrorContext, \
3738 "%s:%d Internal error: no document\n", \
3739 __FILE__, __LINE__); \
3740 } \
3741 else if (ctxt->doc->children == NULL) { \
3742 xmlGenericError(xmlGenericErrorContext, \
3743 "%s:%d Internal error: document without root\n", \
3744 __FILE__, __LINE__); \
3745 } \
3746
3747
3748/**
3749 * xmlXPathNewParserContext:
3750 * @str: the XPath expression
3751 * @ctxt: the XPath context
3752 *
3753 * Create a new xmlXPathParserContext
3754 *
3755 * Returns the xmlXPathParserContext just allocated.
3756 */
3757xmlXPathParserContextPtr
3758xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3759 xmlXPathParserContextPtr ret;
3760
3761 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3762 if (ret == NULL) {
3763 xmlGenericError(xmlGenericErrorContext,
3764 "xmlXPathNewParserContext: out of memory\n");
3765 return(NULL);
3766 }
3767 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3768 ret->cur = ret->base = str;
3769 ret->context = ctxt;
3770
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003771 ret->comp = xmlXPathNewCompExpr();
3772 if (ret->comp == NULL) {
3773 xmlFree(ret->valueTab);
3774 xmlFree(ret);
3775 return(NULL);
3776 }
3777
3778 return(ret);
3779}
3780
3781/**
3782 * xmlXPathCompParserContext:
3783 * @comp: the XPath compiled expression
3784 * @ctxt: the XPath context
3785 *
3786 * Create a new xmlXPathParserContext when processing a compiled expression
3787 *
3788 * Returns the xmlXPathParserContext just allocated.
3789 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003790static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003791xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3792 xmlXPathParserContextPtr ret;
3793
3794 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3795 if (ret == NULL) {
3796 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003797 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003798 return(NULL);
3799 }
3800 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3801
Owen Taylor3473f882001-02-23 17:55:21 +00003802 /* Allocate the value stack */
3803 ret->valueTab = (xmlXPathObjectPtr *)
3804 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003805 if (ret->valueTab == NULL) {
3806 xmlFree(ret);
3807 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003808 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003809 return(NULL);
3810 }
Owen Taylor3473f882001-02-23 17:55:21 +00003811 ret->valueNr = 0;
3812 ret->valueMax = 10;
3813 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003814
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00003815 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003816 ret->comp = comp;
3817
Owen Taylor3473f882001-02-23 17:55:21 +00003818 return(ret);
3819}
3820
3821/**
3822 * xmlXPathFreeParserContext:
3823 * @ctxt: the context to free
3824 *
3825 * Free up an xmlXPathParserContext
3826 */
3827void
3828xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
3829 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003830 xmlFree(ctxt->valueTab);
3831 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003832 if (ctxt->comp)
3833 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00003834 xmlFree(ctxt);
3835}
3836
3837/************************************************************************
3838 * *
3839 * The implicit core function library *
3840 * *
3841 ************************************************************************/
3842
Owen Taylor3473f882001-02-23 17:55:21 +00003843/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00003844 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00003845 * @node: a node pointer
3846 *
3847 * Function computing the beginning of the string value of the node,
3848 * used to speed up comparisons
3849 *
3850 * Returns an int usable as a hash
3851 */
3852static unsigned int
3853xmlXPathNodeValHash(xmlNodePtr node) {
3854 int len = 2;
3855 const xmlChar * string = NULL;
3856 xmlNodePtr tmp = NULL;
3857 unsigned int ret = 0;
3858
3859 if (node == NULL)
3860 return(0);
3861
3862
3863 switch (node->type) {
3864 case XML_COMMENT_NODE:
3865 case XML_PI_NODE:
3866 case XML_CDATA_SECTION_NODE:
3867 case XML_TEXT_NODE:
3868 string = node->content;
3869 if (string == NULL)
3870 return(0);
3871 if (string[0] == 0)
3872 return(0);
3873 return(((unsigned int) string[0]) +
3874 (((unsigned int) string[1]) << 8));
3875 case XML_NAMESPACE_DECL:
3876 string = ((xmlNsPtr)node)->href;
3877 if (string == NULL)
3878 return(0);
3879 if (string[0] == 0)
3880 return(0);
3881 return(((unsigned int) string[0]) +
3882 (((unsigned int) string[1]) << 8));
3883 case XML_ATTRIBUTE_NODE:
3884 tmp = ((xmlAttrPtr) node)->children;
3885 break;
3886 case XML_ELEMENT_NODE:
3887 tmp = node->children;
3888 break;
3889 default:
3890 return(0);
3891 }
3892 while (tmp != NULL) {
3893 switch (tmp->type) {
3894 case XML_COMMENT_NODE:
3895 case XML_PI_NODE:
3896 case XML_CDATA_SECTION_NODE:
3897 case XML_TEXT_NODE:
3898 string = tmp->content;
3899 break;
3900 case XML_NAMESPACE_DECL:
3901 string = ((xmlNsPtr)tmp)->href;
3902 break;
3903 default:
3904 break;
3905 }
3906 if ((string != NULL) && (string[0] != 0)) {
3907 if (string[0] == 0)
3908 return(0);
3909 if (len == 1) {
3910 return(ret + (((unsigned int) string[0]) << 8));
3911 }
3912 if (string[1] == 0) {
3913 len = 1;
3914 ret = (unsigned int) string[0];
3915 } else {
3916 return(((unsigned int) string[0]) +
3917 (((unsigned int) string[1]) << 8));
3918 }
3919 }
3920 /*
3921 * Skip to next node
3922 */
3923 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
3924 if (tmp->children->type != XML_ENTITY_DECL) {
3925 tmp = tmp->children;
3926 continue;
3927 }
3928 }
3929 if (tmp == node)
3930 break;
3931
3932 if (tmp->next != NULL) {
3933 tmp = tmp->next;
3934 continue;
3935 }
3936
3937 do {
3938 tmp = tmp->parent;
3939 if (tmp == NULL)
3940 break;
3941 if (tmp == node) {
3942 tmp = NULL;
3943 break;
3944 }
3945 if (tmp->next != NULL) {
3946 tmp = tmp->next;
3947 break;
3948 }
3949 } while (tmp != NULL);
3950 }
3951 return(ret);
3952}
3953
3954/**
3955 * xmlXPathStringHash:
3956 * @string: a string
3957 *
3958 * Function computing the beginning of the string value of the node,
3959 * used to speed up comparisons
3960 *
3961 * Returns an int usable as a hash
3962 */
3963static unsigned int
3964xmlXPathStringHash(const xmlChar * string) {
3965 if (string == NULL)
3966 return((unsigned int) 0);
3967 if (string[0] == 0)
3968 return(0);
3969 return(((unsigned int) string[0]) +
3970 (((unsigned int) string[1]) << 8));
3971}
3972
3973/**
Owen Taylor3473f882001-02-23 17:55:21 +00003974 * xmlXPathCompareNodeSetFloat:
3975 * @ctxt: the XPath Parser context
3976 * @inf: less than (1) or greater than (0)
3977 * @strict: is the comparison strict
3978 * @arg: the node set
3979 * @f: the value
3980 *
3981 * Implement the compare operation between a nodeset and a number
3982 * @ns < @val (1, 1, ...
3983 * @ns <= @val (1, 0, ...
3984 * @ns > @val (0, 1, ...
3985 * @ns >= @val (0, 0, ...
3986 *
3987 * If one object to be compared is a node-set and the other is a number,
3988 * then the comparison will be true if and only if there is a node in the
3989 * node-set such that the result of performing the comparison on the number
3990 * to be compared and on the result of converting the string-value of that
3991 * node to a number using the number function is true.
3992 *
3993 * Returns 0 or 1 depending on the results of the test.
3994 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003995static int
Owen Taylor3473f882001-02-23 17:55:21 +00003996xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
3997 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
3998 int i, ret = 0;
3999 xmlNodeSetPtr ns;
4000 xmlChar *str2;
4001
4002 if ((f == NULL) || (arg == NULL) ||
4003 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4004 xmlXPathFreeObject(arg);
4005 xmlXPathFreeObject(f);
4006 return(0);
4007 }
4008 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004009 if (ns != NULL) {
4010 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004011 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004012 if (str2 != NULL) {
4013 valuePush(ctxt,
4014 xmlXPathNewString(str2));
4015 xmlFree(str2);
4016 xmlXPathNumberFunction(ctxt, 1);
4017 valuePush(ctxt, xmlXPathObjectCopy(f));
4018 ret = xmlXPathCompareValues(ctxt, inf, strict);
4019 if (ret)
4020 break;
4021 }
4022 }
Owen Taylor3473f882001-02-23 17:55:21 +00004023 }
4024 xmlXPathFreeObject(arg);
4025 xmlXPathFreeObject(f);
4026 return(ret);
4027}
4028
4029/**
4030 * xmlXPathCompareNodeSetString:
4031 * @ctxt: the XPath Parser context
4032 * @inf: less than (1) or greater than (0)
4033 * @strict: is the comparison strict
4034 * @arg: the node set
4035 * @s: the value
4036 *
4037 * Implement the compare operation between a nodeset and a string
4038 * @ns < @val (1, 1, ...
4039 * @ns <= @val (1, 0, ...
4040 * @ns > @val (0, 1, ...
4041 * @ns >= @val (0, 0, ...
4042 *
4043 * If one object to be compared is a node-set and the other is a string,
4044 * then the comparison will be true if and only if there is a node in
4045 * the node-set such that the result of performing the comparison on the
4046 * string-value of the node and the other string is true.
4047 *
4048 * Returns 0 or 1 depending on the results of the test.
4049 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004050static int
Owen Taylor3473f882001-02-23 17:55:21 +00004051xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
4052 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
4053 int i, ret = 0;
4054 xmlNodeSetPtr ns;
4055 xmlChar *str2;
4056
4057 if ((s == NULL) || (arg == NULL) ||
4058 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4059 xmlXPathFreeObject(arg);
4060 xmlXPathFreeObject(s);
4061 return(0);
4062 }
4063 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004064 if (ns != NULL) {
4065 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004066 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004067 if (str2 != NULL) {
4068 valuePush(ctxt,
4069 xmlXPathNewString(str2));
4070 xmlFree(str2);
4071 valuePush(ctxt, xmlXPathObjectCopy(s));
4072 ret = xmlXPathCompareValues(ctxt, inf, strict);
4073 if (ret)
4074 break;
4075 }
4076 }
Owen Taylor3473f882001-02-23 17:55:21 +00004077 }
4078 xmlXPathFreeObject(arg);
4079 xmlXPathFreeObject(s);
4080 return(ret);
4081}
4082
4083/**
4084 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004085 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00004086 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004087 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00004088 * @arg2: the second node set object
4089 *
4090 * Implement the compare operation on nodesets:
4091 *
4092 * If both objects to be compared are node-sets, then the comparison
4093 * will be true if and only if there is a node in the first node-set
4094 * and a node in the second node-set such that the result of performing
4095 * the comparison on the string-values of the two nodes is true.
4096 * ....
4097 * When neither object to be compared is a node-set and the operator
4098 * is <=, <, >= or >, then the objects are compared by converting both
4099 * objects to numbers and comparing the numbers according to IEEE 754.
4100 * ....
4101 * The number function converts its argument to a number as follows:
4102 * - a string that consists of optional whitespace followed by an
4103 * optional minus sign followed by a Number followed by whitespace
4104 * is converted to the IEEE 754 number that is nearest (according
4105 * to the IEEE 754 round-to-nearest rule) to the mathematical value
4106 * represented by the string; any other string is converted to NaN
4107 *
4108 * Conclusion all nodes need to be converted first to their string value
4109 * and then the comparison must be done when possible
4110 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004111static int
4112xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00004113 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4114 int i, j, init = 0;
4115 double val1;
4116 double *values2;
4117 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004118 xmlNodeSetPtr ns1;
4119 xmlNodeSetPtr ns2;
4120
4121 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004122 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4123 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004124 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004125 }
Owen Taylor3473f882001-02-23 17:55:21 +00004126 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004127 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4128 xmlXPathFreeObject(arg1);
4129 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004130 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004131 }
Owen Taylor3473f882001-02-23 17:55:21 +00004132
4133 ns1 = arg1->nodesetval;
4134 ns2 = arg2->nodesetval;
4135
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004136 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004137 xmlXPathFreeObject(arg1);
4138 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004139 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004140 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004141 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004142 xmlXPathFreeObject(arg1);
4143 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004144 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004145 }
Owen Taylor3473f882001-02-23 17:55:21 +00004146
4147 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4148 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004149 xmlXPathFreeObject(arg1);
4150 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004151 return(0);
4152 }
4153 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004154 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004155 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004156 continue;
4157 for (j = 0;j < ns2->nodeNr;j++) {
4158 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004159 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004160 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004161 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004162 continue;
4163 if (inf && strict)
4164 ret = (val1 < values2[j]);
4165 else if (inf && !strict)
4166 ret = (val1 <= values2[j]);
4167 else if (!inf && strict)
4168 ret = (val1 > values2[j]);
4169 else if (!inf && !strict)
4170 ret = (val1 >= values2[j]);
4171 if (ret)
4172 break;
4173 }
4174 if (ret)
4175 break;
4176 init = 1;
4177 }
4178 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004179 xmlXPathFreeObject(arg1);
4180 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004181 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004182}
4183
4184/**
4185 * xmlXPathCompareNodeSetValue:
4186 * @ctxt: the XPath Parser context
4187 * @inf: less than (1) or greater than (0)
4188 * @strict: is the comparison strict
4189 * @arg: the node set
4190 * @val: the value
4191 *
4192 * Implement the compare operation between a nodeset and a value
4193 * @ns < @val (1, 1, ...
4194 * @ns <= @val (1, 0, ...
4195 * @ns > @val (0, 1, ...
4196 * @ns >= @val (0, 0, ...
4197 *
4198 * If one object to be compared is a node-set and the other is a boolean,
4199 * then the comparison will be true if and only if the result of performing
4200 * the comparison on the boolean and on the result of converting
4201 * the node-set to a boolean using the boolean function is true.
4202 *
4203 * Returns 0 or 1 depending on the results of the test.
4204 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004205static int
Owen Taylor3473f882001-02-23 17:55:21 +00004206xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4207 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4208 if ((val == NULL) || (arg == NULL) ||
4209 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4210 return(0);
4211
4212 switch(val->type) {
4213 case XPATH_NUMBER:
4214 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4215 case XPATH_NODESET:
4216 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004217 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004218 case XPATH_STRING:
4219 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4220 case XPATH_BOOLEAN:
4221 valuePush(ctxt, arg);
4222 xmlXPathBooleanFunction(ctxt, 1);
4223 valuePush(ctxt, val);
4224 return(xmlXPathCompareValues(ctxt, inf, strict));
4225 default:
4226 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004227 }
4228 return(0);
4229}
4230
4231/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004232 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00004233 * @arg: the nodeset object argument
4234 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00004235 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004236 *
4237 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4238 * If one object to be compared is a node-set and the other is a string,
4239 * then the comparison will be true if and only if there is a node in
4240 * the node-set such that the result of performing the comparison on the
4241 * string-value of the node and the other string is true.
4242 *
4243 * Returns 0 or 1 depending on the results of the test.
4244 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004245static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004246xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004247{
Owen Taylor3473f882001-02-23 17:55:21 +00004248 int i;
4249 xmlNodeSetPtr ns;
4250 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004251 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004252
4253 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004254 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4255 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004256 ns = arg->nodesetval;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004257 hash = xmlXPathStringHash(str);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004258 if (ns == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004259 return (0);
Daniel Veillard73c9c042001-07-05 20:02:54 +00004260 if (ns->nodeNr <= 0) {
4261 if (hash == 0)
William M. Brack0c022ad2002-07-12 00:56:01 +00004262 return(neq ^ 1);
4263 return(neq);
Daniel Veillard73c9c042001-07-05 20:02:54 +00004264 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004265 for (i = 0; i < ns->nodeNr; i++) {
4266 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4267 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4268 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4269 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004270 if (neq)
4271 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004272 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00004273 } else if (neq) {
4274 if (str2 != NULL)
4275 xmlFree(str2);
4276 return (1);
4277 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004278 if (str2 != NULL)
4279 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004280 } else if (neq)
4281 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00004282 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004283 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004284}
4285
4286/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004287 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00004288 * @arg: the nodeset object argument
4289 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00004290 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004291 *
4292 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4293 * If one object to be compared is a node-set and the other is a number,
4294 * then the comparison will be true if and only if there is a node in
4295 * the node-set such that the result of performing the comparison on the
4296 * number to be compared and on the result of converting the string-value
4297 * of that node to a number using the number function is true.
4298 *
4299 * Returns 0 or 1 depending on the results of the test.
4300 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004301static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004302xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
4303 xmlXPathObjectPtr arg, double f, int neq) {
4304 int i, ret=0;
4305 xmlNodeSetPtr ns;
4306 xmlChar *str2;
4307 xmlXPathObjectPtr val;
4308 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00004309
4310 if ((arg == NULL) ||
4311 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4312 return(0);
4313
William M. Brack0c022ad2002-07-12 00:56:01 +00004314 ns = arg->nodesetval;
4315 if (ns != NULL) {
4316 for (i=0;i<ns->nodeNr;i++) {
4317 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4318 if (str2 != NULL) {
4319 valuePush(ctxt, xmlXPathNewString(str2));
4320 xmlFree(str2);
4321 xmlXPathNumberFunction(ctxt, 1);
4322 val = valuePop(ctxt);
4323 v = val->floatval;
4324 xmlXPathFreeObject(val);
4325 if (!xmlXPathIsNaN(v)) {
4326 if ((!neq) && (v==f)) {
4327 ret = 1;
4328 break;
4329 } else if ((neq) && (v!=f)) {
4330 ret = 1;
4331 break;
4332 }
4333 }
4334 }
4335 }
4336 }
4337
4338 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004339}
4340
4341
4342/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004343 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00004344 * @arg1: first nodeset object argument
4345 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00004346 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004347 *
William M. Brack0c022ad2002-07-12 00:56:01 +00004348 * Implement the equal / not equal operation on XPath nodesets:
4349 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00004350 * If both objects to be compared are node-sets, then the comparison
4351 * will be true if and only if there is a node in the first node-set and
4352 * a node in the second node-set such that the result of performing the
4353 * comparison on the string-values of the two nodes is true.
4354 *
4355 * (needless to say, this is a costly operation)
4356 *
4357 * Returns 0 or 1 depending on the results of the test.
4358 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004359static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004360xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00004361 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004362 unsigned int *hashs1;
4363 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004364 xmlChar **values1;
4365 xmlChar **values2;
4366 int ret = 0;
4367 xmlNodeSetPtr ns1;
4368 xmlNodeSetPtr ns2;
4369
4370 if ((arg1 == NULL) ||
4371 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4372 return(0);
4373 if ((arg2 == NULL) ||
4374 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4375 return(0);
4376
4377 ns1 = arg1->nodesetval;
4378 ns2 = arg2->nodesetval;
4379
Daniel Veillard911f49a2001-04-07 15:39:35 +00004380 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004381 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004382 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004383 return(0);
4384
4385 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00004386 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00004387 */
William M. Brack0c022ad2002-07-12 00:56:01 +00004388 if (neq == 0)
4389 for (i = 0;i < ns1->nodeNr;i++)
4390 for (j = 0;j < ns2->nodeNr;j++)
4391 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4392 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00004393
4394 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
4395 if (values1 == NULL)
4396 return(0);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004397 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4398 if (hashs1 == NULL) {
4399 xmlFree(values1);
4400 return(0);
4401 }
Owen Taylor3473f882001-02-23 17:55:21 +00004402 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4403 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4404 if (values2 == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004405 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004406 xmlFree(values1);
4407 return(0);
4408 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004409 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4410 if (hashs2 == NULL) {
4411 xmlFree(hashs1);
4412 xmlFree(values1);
4413 xmlFree(values2);
4414 return(0);
4415 }
Owen Taylor3473f882001-02-23 17:55:21 +00004416 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4417 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004418 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004419 for (j = 0;j < ns2->nodeNr;j++) {
4420 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004421 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004422 if (hashs1[i] != hashs2[j]) {
4423 if (neq) {
4424 ret = 1;
4425 break;
4426 }
4427 }
4428 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004429 if (values1[i] == NULL)
4430 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4431 if (values2[j] == NULL)
4432 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004433 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004434 if (ret)
4435 break;
4436 }
Owen Taylor3473f882001-02-23 17:55:21 +00004437 }
4438 if (ret)
4439 break;
4440 }
4441 for (i = 0;i < ns1->nodeNr;i++)
4442 if (values1[i] != NULL)
4443 xmlFree(values1[i]);
4444 for (j = 0;j < ns2->nodeNr;j++)
4445 if (values2[j] != NULL)
4446 xmlFree(values2[j]);
4447 xmlFree(values1);
4448 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004449 xmlFree(hashs1);
4450 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004451 return(ret);
4452}
4453
William M. Brack0c022ad2002-07-12 00:56:01 +00004454static int
4455xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
4456 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00004457 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00004458 /*
4459 *At this point we are assured neither arg1 nor arg2
4460 *is a nodeset, so we can just pick the appropriate routine.
4461 */
Owen Taylor3473f882001-02-23 17:55:21 +00004462 switch (arg1->type) {
4463 case XPATH_UNDEFINED:
4464#ifdef DEBUG_EXPR
4465 xmlGenericError(xmlGenericErrorContext,
4466 "Equal: undefined\n");
4467#endif
4468 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004469 case XPATH_BOOLEAN:
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:
4478#ifdef DEBUG_EXPR
4479 xmlGenericError(xmlGenericErrorContext,
4480 "Equal: %d boolean %d \n",
4481 arg1->boolval, arg2->boolval);
4482#endif
4483 ret = (arg1->boolval == arg2->boolval);
4484 break;
4485 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00004486 ret = (arg1->boolval ==
4487 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004488 break;
4489 case XPATH_STRING:
4490 if ((arg2->stringval == NULL) ||
4491 (arg2->stringval[0] == 0)) ret = 0;
4492 else
4493 ret = 1;
4494 ret = (arg1->boolval == ret);
4495 break;
4496 case XPATH_USERS:
4497 case XPATH_POINT:
4498 case XPATH_RANGE:
4499 case XPATH_LOCATIONSET:
4500 TODO
4501 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004502 case XPATH_NODESET:
4503 case XPATH_XSLT_TREE:
4504 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004505 }
4506 break;
4507 case XPATH_NUMBER:
4508 switch (arg2->type) {
4509 case XPATH_UNDEFINED:
4510#ifdef DEBUG_EXPR
4511 xmlGenericError(xmlGenericErrorContext,
4512 "Equal: undefined\n");
4513#endif
4514 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004515 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00004516 ret = (arg2->boolval==
4517 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004518 break;
4519 case XPATH_STRING:
4520 valuePush(ctxt, arg2);
4521 xmlXPathNumberFunction(ctxt, 1);
4522 arg2 = valuePop(ctxt);
4523 /* no break on purpose */
4524 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004525 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004526 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4527 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004528 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4529 if (xmlXPathIsInf(arg2->floatval) == 1)
4530 ret = 1;
4531 else
4532 ret = 0;
4533 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4534 if (xmlXPathIsInf(arg2->floatval) == -1)
4535 ret = 1;
4536 else
4537 ret = 0;
4538 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4539 if (xmlXPathIsInf(arg1->floatval) == 1)
4540 ret = 1;
4541 else
4542 ret = 0;
4543 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4544 if (xmlXPathIsInf(arg1->floatval) == -1)
4545 ret = 1;
4546 else
4547 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004548 } else {
4549 ret = (arg1->floatval == arg2->floatval);
4550 }
Owen Taylor3473f882001-02-23 17:55:21 +00004551 break;
4552 case XPATH_USERS:
4553 case XPATH_POINT:
4554 case XPATH_RANGE:
4555 case XPATH_LOCATIONSET:
4556 TODO
4557 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004558 case XPATH_NODESET:
4559 case XPATH_XSLT_TREE:
4560 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004561 }
4562 break;
4563 case XPATH_STRING:
4564 switch (arg2->type) {
4565 case XPATH_UNDEFINED:
4566#ifdef DEBUG_EXPR
4567 xmlGenericError(xmlGenericErrorContext,
4568 "Equal: undefined\n");
4569#endif
4570 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004571 case XPATH_BOOLEAN:
4572 if ((arg1->stringval == NULL) ||
4573 (arg1->stringval[0] == 0)) ret = 0;
4574 else
4575 ret = 1;
4576 ret = (arg2->boolval == ret);
4577 break;
4578 case XPATH_STRING:
4579 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4580 break;
4581 case XPATH_NUMBER:
4582 valuePush(ctxt, arg1);
4583 xmlXPathNumberFunction(ctxt, 1);
4584 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004585 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004586 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4587 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004588 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4589 if (xmlXPathIsInf(arg2->floatval) == 1)
4590 ret = 1;
4591 else
4592 ret = 0;
4593 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4594 if (xmlXPathIsInf(arg2->floatval) == -1)
4595 ret = 1;
4596 else
4597 ret = 0;
4598 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4599 if (xmlXPathIsInf(arg1->floatval) == 1)
4600 ret = 1;
4601 else
4602 ret = 0;
4603 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4604 if (xmlXPathIsInf(arg1->floatval) == -1)
4605 ret = 1;
4606 else
4607 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004608 } else {
4609 ret = (arg1->floatval == arg2->floatval);
4610 }
Owen Taylor3473f882001-02-23 17:55:21 +00004611 break;
4612 case XPATH_USERS:
4613 case XPATH_POINT:
4614 case XPATH_RANGE:
4615 case XPATH_LOCATIONSET:
4616 TODO
4617 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004618 case XPATH_NODESET:
4619 case XPATH_XSLT_TREE:
4620 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004621 }
4622 break;
4623 case XPATH_USERS:
4624 case XPATH_POINT:
4625 case XPATH_RANGE:
4626 case XPATH_LOCATIONSET:
4627 TODO
4628 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004629 case XPATH_NODESET:
4630 case XPATH_XSLT_TREE:
4631 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004632 }
4633 xmlXPathFreeObject(arg1);
4634 xmlXPathFreeObject(arg2);
4635 return(ret);
4636}
4637
William M. Brack0c022ad2002-07-12 00:56:01 +00004638/**
4639 * xmlXPathEqualValues:
4640 * @ctxt: the XPath Parser context
4641 *
4642 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4643 *
4644 * Returns 0 or 1 depending on the results of the test.
4645 */
4646int
4647xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4648 xmlXPathObjectPtr arg1, arg2, argtmp;
4649 int ret = 0;
4650
4651 arg2 = valuePop(ctxt);
4652 arg1 = valuePop(ctxt);
4653 if ((arg1 == NULL) || (arg2 == NULL)) {
4654 if (arg1 != NULL)
4655 xmlXPathFreeObject(arg1);
4656 else
4657 xmlXPathFreeObject(arg2);
4658 XP_ERROR0(XPATH_INVALID_OPERAND);
4659 }
4660
4661 if (arg1 == arg2) {
4662#ifdef DEBUG_EXPR
4663 xmlGenericError(xmlGenericErrorContext,
4664 "Equal: by pointer\n");
4665#endif
4666 return(1);
4667 }
4668
4669 /*
4670 *If either argument is a nodeset, it's a 'special case'
4671 */
4672 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4673 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4674 /*
4675 *Hack it to assure arg1 is the nodeset
4676 */
4677 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4678 argtmp = arg2;
4679 arg2 = arg1;
4680 arg1 = argtmp;
4681 }
4682 switch (arg2->type) {
4683 case XPATH_UNDEFINED:
4684#ifdef DEBUG_EXPR
4685 xmlGenericError(xmlGenericErrorContext,
4686 "Equal: undefined\n");
4687#endif
4688 break;
4689 case XPATH_NODESET:
4690 case XPATH_XSLT_TREE:
4691 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
4692 break;
4693 case XPATH_BOOLEAN:
4694 if ((arg1->nodesetval == NULL) ||
4695 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4696 else
4697 ret = 1;
4698 ret = (ret == arg2->boolval);
4699 break;
4700 case XPATH_NUMBER:
4701 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
4702 break;
4703 case XPATH_STRING:
4704 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
4705 break;
4706 case XPATH_USERS:
4707 case XPATH_POINT:
4708 case XPATH_RANGE:
4709 case XPATH_LOCATIONSET:
4710 TODO
4711 break;
4712 }
4713 xmlXPathFreeObject(arg1);
4714 xmlXPathFreeObject(arg2);
4715 return(ret);
4716 }
4717
4718 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4719}
4720
4721/**
4722 * xmlXPathNotEqualValues:
4723 * @ctxt: the XPath Parser context
4724 *
4725 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4726 *
4727 * Returns 0 or 1 depending on the results of the test.
4728 */
4729int
4730xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
4731 xmlXPathObjectPtr arg1, arg2, argtmp;
4732 int ret = 0;
4733
4734 arg2 = valuePop(ctxt);
4735 arg1 = valuePop(ctxt);
4736 if ((arg1 == NULL) || (arg2 == NULL)) {
4737 if (arg1 != NULL)
4738 xmlXPathFreeObject(arg1);
4739 else
4740 xmlXPathFreeObject(arg2);
4741 XP_ERROR0(XPATH_INVALID_OPERAND);
4742 }
4743
4744 if (arg1 == arg2) {
4745#ifdef DEBUG_EXPR
4746 xmlGenericError(xmlGenericErrorContext,
4747 "NotEqual: by pointer\n");
4748#endif
4749 return(0);
4750 }
4751
4752 /*
4753 *If either argument is a nodeset, it's a 'special case'
4754 */
4755 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4756 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4757 /*
4758 *Hack it to assure arg1 is the nodeset
4759 */
4760 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4761 argtmp = arg2;
4762 arg2 = arg1;
4763 arg1 = argtmp;
4764 }
4765 switch (arg2->type) {
4766 case XPATH_UNDEFINED:
4767#ifdef DEBUG_EXPR
4768 xmlGenericError(xmlGenericErrorContext,
4769 "NotEqual: undefined\n");
4770#endif
4771 break;
4772 case XPATH_NODESET:
4773 case XPATH_XSLT_TREE:
4774 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
4775 break;
4776 case XPATH_BOOLEAN:
4777 if ((arg1->nodesetval == NULL) ||
4778 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4779 else
4780 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00004781 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00004782 break;
4783 case XPATH_NUMBER:
4784 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
4785 break;
4786 case XPATH_STRING:
4787 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
4788 break;
4789 case XPATH_USERS:
4790 case XPATH_POINT:
4791 case XPATH_RANGE:
4792 case XPATH_LOCATIONSET:
4793 TODO
4794 break;
4795 }
4796 xmlXPathFreeObject(arg1);
4797 xmlXPathFreeObject(arg2);
4798 return(ret);
4799 }
4800
4801 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4802}
Owen Taylor3473f882001-02-23 17:55:21 +00004803
4804/**
4805 * xmlXPathCompareValues:
4806 * @ctxt: the XPath Parser context
4807 * @inf: less than (1) or greater than (0)
4808 * @strict: is the comparison strict
4809 *
4810 * Implement the compare operation on XPath objects:
4811 * @arg1 < @arg2 (1, 1, ...
4812 * @arg1 <= @arg2 (1, 0, ...
4813 * @arg1 > @arg2 (0, 1, ...
4814 * @arg1 >= @arg2 (0, 0, ...
4815 *
4816 * When neither object to be compared is a node-set and the operator is
4817 * <=, <, >=, >, then the objects are compared by converted both objects
4818 * to numbers and comparing the numbers according to IEEE 754. The <
4819 * comparison will be true if and only if the first number is less than the
4820 * second number. The <= comparison will be true if and only if the first
4821 * number is less than or equal to the second number. The > comparison
4822 * will be true if and only if the first number is greater than the second
4823 * number. The >= comparison will be true if and only if the first number
4824 * is greater than or equal to the second number.
4825 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004826 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00004827 */
4828int
4829xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004830 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004831 xmlXPathObjectPtr arg1, arg2;
4832
William M. Brack0c022ad2002-07-12 00:56:01 +00004833 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00004834 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00004835 if ((arg1 == NULL) || (arg2 == NULL)) {
4836 if (arg1 != NULL)
4837 xmlXPathFreeObject(arg1);
4838 else
4839 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004840 XP_ERROR0(XPATH_INVALID_OPERAND);
4841 }
4842
William M. Brack0c022ad2002-07-12 00:56:01 +00004843 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4844 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4845 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
4846 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004847 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004848 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00004849 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004850 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
4851 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004852 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004853 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
4854 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00004855 }
4856 }
4857 return(ret);
4858 }
4859
4860 if (arg1->type != XPATH_NUMBER) {
4861 valuePush(ctxt, arg1);
4862 xmlXPathNumberFunction(ctxt, 1);
4863 arg1 = valuePop(ctxt);
4864 }
4865 if (arg1->type != XPATH_NUMBER) {
4866 xmlXPathFreeObject(arg1);
4867 xmlXPathFreeObject(arg2);
4868 XP_ERROR0(XPATH_INVALID_OPERAND);
4869 }
4870 if (arg2->type != XPATH_NUMBER) {
4871 valuePush(ctxt, arg2);
4872 xmlXPathNumberFunction(ctxt, 1);
4873 arg2 = valuePop(ctxt);
4874 }
4875 if (arg2->type != XPATH_NUMBER) {
4876 xmlXPathFreeObject(arg1);
4877 xmlXPathFreeObject(arg2);
4878 XP_ERROR0(XPATH_INVALID_OPERAND);
4879 }
4880 /*
4881 * Add tests for infinity and nan
4882 * => feedback on 3.4 for Inf and NaN
4883 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004884 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00004885 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004886 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004887 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004888 arg1i=xmlXPathIsInf(arg1->floatval);
4889 arg2i=xmlXPathIsInf(arg2->floatval);
4890 if (inf && strict) {
4891 if ((arg1i == -1 && arg2i != -1) ||
4892 (arg2i == 1 && arg1i != 1)) {
4893 ret = 1;
4894 } else if (arg1i == 0 && arg2i == 0) {
4895 ret = (arg1->floatval < arg2->floatval);
4896 } else {
4897 ret = 0;
4898 }
4899 }
4900 else if (inf && !strict) {
4901 if (arg1i == -1 || arg2i == 1) {
4902 ret = 1;
4903 } else if (arg1i == 0 && arg2i == 0) {
4904 ret = (arg1->floatval <= arg2->floatval);
4905 } else {
4906 ret = 0;
4907 }
4908 }
4909 else if (!inf && strict) {
4910 if ((arg1i == 1 && arg2i != 1) ||
4911 (arg2i == -1 && arg1i != -1)) {
4912 ret = 1;
4913 } else if (arg1i == 0 && arg2i == 0) {
4914 ret = (arg1->floatval > arg2->floatval);
4915 } else {
4916 ret = 0;
4917 }
4918 }
4919 else if (!inf && !strict) {
4920 if (arg1i == 1 || arg2i == -1) {
4921 ret = 1;
4922 } else if (arg1i == 0 && arg2i == 0) {
4923 ret = (arg1->floatval >= arg2->floatval);
4924 } else {
4925 ret = 0;
4926 }
4927 }
Daniel Veillard21458c82002-03-27 16:12:22 +00004928 }
Owen Taylor3473f882001-02-23 17:55:21 +00004929 xmlXPathFreeObject(arg1);
4930 xmlXPathFreeObject(arg2);
4931 return(ret);
4932}
4933
4934/**
4935 * xmlXPathValueFlipSign:
4936 * @ctxt: the XPath Parser context
4937 *
4938 * Implement the unary - operation on an XPath object
4939 * The numeric operators convert their operands to numbers as if
4940 * by calling the number function.
4941 */
4942void
4943xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004944 CAST_TO_NUMBER;
4945 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00004946 if (xmlXPathIsNaN(ctxt->value->floatval))
4947 ctxt->value->floatval=xmlXPathNAN;
4948 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
4949 ctxt->value->floatval=xmlXPathNINF;
4950 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
4951 ctxt->value->floatval=xmlXPathPINF;
4952 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00004953 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
4954 ctxt->value->floatval = xmlXPathNZERO;
4955 else
4956 ctxt->value->floatval = 0;
4957 }
4958 else
4959 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00004960}
4961
4962/**
4963 * xmlXPathAddValues:
4964 * @ctxt: the XPath Parser context
4965 *
4966 * Implement the add operation on XPath objects:
4967 * The numeric operators convert their operands to numbers as if
4968 * by calling the number function.
4969 */
4970void
4971xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
4972 xmlXPathObjectPtr arg;
4973 double val;
4974
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004975 arg = valuePop(ctxt);
4976 if (arg == NULL)
4977 XP_ERROR(XPATH_INVALID_OPERAND);
4978 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004979 xmlXPathFreeObject(arg);
4980
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004981 CAST_TO_NUMBER;
4982 CHECK_TYPE(XPATH_NUMBER);
4983 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00004984}
4985
4986/**
4987 * xmlXPathSubValues:
4988 * @ctxt: the XPath Parser context
4989 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004990 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00004991 * The numeric operators convert their operands to numbers as if
4992 * by calling the number function.
4993 */
4994void
4995xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
4996 xmlXPathObjectPtr arg;
4997 double val;
4998
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004999 arg = valuePop(ctxt);
5000 if (arg == NULL)
5001 XP_ERROR(XPATH_INVALID_OPERAND);
5002 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005003 xmlXPathFreeObject(arg);
5004
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005005 CAST_TO_NUMBER;
5006 CHECK_TYPE(XPATH_NUMBER);
5007 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005008}
5009
5010/**
5011 * xmlXPathMultValues:
5012 * @ctxt: the XPath Parser context
5013 *
5014 * Implement the multiply operation on XPath objects:
5015 * The numeric operators convert their operands to numbers as if
5016 * by calling the number function.
5017 */
5018void
5019xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
5020 xmlXPathObjectPtr arg;
5021 double val;
5022
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005023 arg = valuePop(ctxt);
5024 if (arg == NULL)
5025 XP_ERROR(XPATH_INVALID_OPERAND);
5026 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005027 xmlXPathFreeObject(arg);
5028
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005029 CAST_TO_NUMBER;
5030 CHECK_TYPE(XPATH_NUMBER);
5031 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005032}
5033
5034/**
5035 * xmlXPathDivValues:
5036 * @ctxt: the XPath Parser context
5037 *
5038 * Implement the div operation on XPath objects @arg1 / @arg2:
5039 * The numeric operators convert their operands to numbers as if
5040 * by calling the number function.
5041 */
5042void
5043xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
5044 xmlXPathObjectPtr arg;
5045 double val;
5046
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005047 arg = valuePop(ctxt);
5048 if (arg == NULL)
5049 XP_ERROR(XPATH_INVALID_OPERAND);
5050 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005051 xmlXPathFreeObject(arg);
5052
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005053 CAST_TO_NUMBER;
5054 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005055 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
5056 ctxt->value->floatval = xmlXPathNAN;
5057 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005058 if (ctxt->value->floatval == 0)
5059 ctxt->value->floatval = xmlXPathNAN;
5060 else if (ctxt->value->floatval > 0)
5061 ctxt->value->floatval = xmlXPathNINF;
5062 else if (ctxt->value->floatval < 0)
5063 ctxt->value->floatval = xmlXPathPINF;
5064 }
5065 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00005066 if (ctxt->value->floatval == 0)
5067 ctxt->value->floatval = xmlXPathNAN;
5068 else if (ctxt->value->floatval > 0)
5069 ctxt->value->floatval = xmlXPathPINF;
5070 else if (ctxt->value->floatval < 0)
5071 ctxt->value->floatval = xmlXPathNINF;
5072 } else
5073 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005074}
5075
5076/**
5077 * xmlXPathModValues:
5078 * @ctxt: the XPath Parser context
5079 *
5080 * Implement the mod operation on XPath objects: @arg1 / @arg2
5081 * The numeric operators convert their operands to numbers as if
5082 * by calling the number function.
5083 */
5084void
5085xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
5086 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005087 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00005088
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005089 arg = valuePop(ctxt);
5090 if (arg == NULL)
5091 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005092 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005093 xmlXPathFreeObject(arg);
5094
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005095 CAST_TO_NUMBER;
5096 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005097 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00005098 if (arg2 == 0)
5099 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005100 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00005101 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005102 }
Owen Taylor3473f882001-02-23 17:55:21 +00005103}
5104
5105/************************************************************************
5106 * *
5107 * The traversal functions *
5108 * *
5109 ************************************************************************/
5110
Owen Taylor3473f882001-02-23 17:55:21 +00005111/*
5112 * A traversal function enumerates nodes along an axis.
5113 * Initially it must be called with NULL, and it indicates
5114 * termination on the axis by returning NULL.
5115 */
5116typedef xmlNodePtr (*xmlXPathTraversalFunction)
5117 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
5118
5119/**
5120 * xmlXPathNextSelf:
5121 * @ctxt: the XPath Parser context
5122 * @cur: the current node in the traversal
5123 *
5124 * Traversal function for the "self" direction
5125 * The self axis contains just the context node itself
5126 *
5127 * Returns the next element following that axis
5128 */
5129xmlNodePtr
5130xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5131 if (cur == NULL)
5132 return(ctxt->context->node);
5133 return(NULL);
5134}
5135
5136/**
5137 * xmlXPathNextChild:
5138 * @ctxt: the XPath Parser context
5139 * @cur: the current node in the traversal
5140 *
5141 * Traversal function for the "child" direction
5142 * The child axis contains the children of the context node in document order.
5143 *
5144 * Returns the next element following that axis
5145 */
5146xmlNodePtr
5147xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5148 if (cur == NULL) {
5149 if (ctxt->context->node == NULL) return(NULL);
5150 switch (ctxt->context->node->type) {
5151 case XML_ELEMENT_NODE:
5152 case XML_TEXT_NODE:
5153 case XML_CDATA_SECTION_NODE:
5154 case XML_ENTITY_REF_NODE:
5155 case XML_ENTITY_NODE:
5156 case XML_PI_NODE:
5157 case XML_COMMENT_NODE:
5158 case XML_NOTATION_NODE:
5159 case XML_DTD_NODE:
5160 return(ctxt->context->node->children);
5161 case XML_DOCUMENT_NODE:
5162 case XML_DOCUMENT_TYPE_NODE:
5163 case XML_DOCUMENT_FRAG_NODE:
5164 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005165#ifdef LIBXML_DOCB_ENABLED
5166 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005167#endif
5168 return(((xmlDocPtr) ctxt->context->node)->children);
5169 case XML_ELEMENT_DECL:
5170 case XML_ATTRIBUTE_DECL:
5171 case XML_ENTITY_DECL:
5172 case XML_ATTRIBUTE_NODE:
5173 case XML_NAMESPACE_DECL:
5174 case XML_XINCLUDE_START:
5175 case XML_XINCLUDE_END:
5176 return(NULL);
5177 }
5178 return(NULL);
5179 }
5180 if ((cur->type == XML_DOCUMENT_NODE) ||
5181 (cur->type == XML_HTML_DOCUMENT_NODE))
5182 return(NULL);
5183 return(cur->next);
5184}
5185
5186/**
5187 * xmlXPathNextDescendant:
5188 * @ctxt: the XPath Parser context
5189 * @cur: the current node in the traversal
5190 *
5191 * Traversal function for the "descendant" direction
5192 * the descendant axis contains the descendants of the context node in document
5193 * order; a descendant is a child or a child of a child and so on.
5194 *
5195 * Returns the next element following that axis
5196 */
5197xmlNodePtr
5198xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5199 if (cur == NULL) {
5200 if (ctxt->context->node == NULL)
5201 return(NULL);
5202 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5203 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5204 return(NULL);
5205
5206 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5207 return(ctxt->context->doc->children);
5208 return(ctxt->context->node->children);
5209 }
5210
Daniel Veillard567e1b42001-08-01 15:53:47 +00005211 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00005212 /*
5213 * Do not descend on entities declarations
5214 */
5215 if (cur->children->type != XML_ENTITY_DECL) {
5216 cur = cur->children;
5217 /*
5218 * Skip DTDs
5219 */
5220 if (cur->type != XML_DTD_NODE)
5221 return(cur);
5222 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00005223 }
5224
5225 if (cur == ctxt->context->node) return(NULL);
5226
Daniel Veillard68e9e742002-11-16 15:35:11 +00005227 while (cur->next != NULL) {
5228 cur = cur->next;
5229 if ((cur->type != XML_ENTITY_DECL) &&
5230 (cur->type != XML_DTD_NODE))
5231 return(cur);
5232 }
Owen Taylor3473f882001-02-23 17:55:21 +00005233
5234 do {
5235 cur = cur->parent;
5236 if (cur == NULL) return(NULL);
5237 if (cur == ctxt->context->node) return(NULL);
5238 if (cur->next != NULL) {
5239 cur = cur->next;
5240 return(cur);
5241 }
5242 } while (cur != NULL);
5243 return(cur);
5244}
5245
5246/**
5247 * xmlXPathNextDescendantOrSelf:
5248 * @ctxt: the XPath Parser context
5249 * @cur: the current node in the traversal
5250 *
5251 * Traversal function for the "descendant-or-self" direction
5252 * the descendant-or-self axis contains the context node and the descendants
5253 * of the context node in document order; thus the context node is the first
5254 * node on the axis, and the first child of the context node is the second node
5255 * on the axis
5256 *
5257 * Returns the next element following that axis
5258 */
5259xmlNodePtr
5260xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5261 if (cur == NULL) {
5262 if (ctxt->context->node == NULL)
5263 return(NULL);
5264 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5265 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5266 return(NULL);
5267 return(ctxt->context->node);
5268 }
5269
5270 return(xmlXPathNextDescendant(ctxt, cur));
5271}
5272
5273/**
5274 * xmlXPathNextParent:
5275 * @ctxt: the XPath Parser context
5276 * @cur: the current node in the traversal
5277 *
5278 * Traversal function for the "parent" direction
5279 * The parent axis contains the parent of the context node, if there is one.
5280 *
5281 * Returns the next element following that axis
5282 */
5283xmlNodePtr
5284xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5285 /*
5286 * the parent of an attribute or namespace node is the element
5287 * to which the attribute or namespace node is attached
5288 * Namespace handling !!!
5289 */
5290 if (cur == NULL) {
5291 if (ctxt->context->node == NULL) return(NULL);
5292 switch (ctxt->context->node->type) {
5293 case XML_ELEMENT_NODE:
5294 case XML_TEXT_NODE:
5295 case XML_CDATA_SECTION_NODE:
5296 case XML_ENTITY_REF_NODE:
5297 case XML_ENTITY_NODE:
5298 case XML_PI_NODE:
5299 case XML_COMMENT_NODE:
5300 case XML_NOTATION_NODE:
5301 case XML_DTD_NODE:
5302 case XML_ELEMENT_DECL:
5303 case XML_ATTRIBUTE_DECL:
5304 case XML_XINCLUDE_START:
5305 case XML_XINCLUDE_END:
5306 case XML_ENTITY_DECL:
5307 if (ctxt->context->node->parent == NULL)
5308 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005309 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005310 ((ctxt->context->node->parent->name[0] == ' ') ||
5311 (xmlStrEqual(ctxt->context->node->parent->name,
5312 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005313 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005314 return(ctxt->context->node->parent);
5315 case XML_ATTRIBUTE_NODE: {
5316 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5317
5318 return(att->parent);
5319 }
5320 case XML_DOCUMENT_NODE:
5321 case XML_DOCUMENT_TYPE_NODE:
5322 case XML_DOCUMENT_FRAG_NODE:
5323 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005324#ifdef LIBXML_DOCB_ENABLED
5325 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005326#endif
5327 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005328 case XML_NAMESPACE_DECL: {
5329 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5330
5331 if ((ns->next != NULL) &&
5332 (ns->next->type != XML_NAMESPACE_DECL))
5333 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005334 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005335 }
Owen Taylor3473f882001-02-23 17:55:21 +00005336 }
5337 }
5338 return(NULL);
5339}
5340
5341/**
5342 * xmlXPathNextAncestor:
5343 * @ctxt: the XPath Parser context
5344 * @cur: the current node in the traversal
5345 *
5346 * Traversal function for the "ancestor" direction
5347 * the ancestor axis contains the ancestors of the context node; the ancestors
5348 * of the context node consist of the parent of context node and the parent's
5349 * parent and so on; the nodes are ordered in reverse document order; thus the
5350 * parent is the first node on the axis, and the parent's parent is the second
5351 * node on the axis
5352 *
5353 * Returns the next element following that axis
5354 */
5355xmlNodePtr
5356xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5357 /*
5358 * the parent of an attribute or namespace node is the element
5359 * to which the attribute or namespace node is attached
5360 * !!!!!!!!!!!!!
5361 */
5362 if (cur == NULL) {
5363 if (ctxt->context->node == NULL) return(NULL);
5364 switch (ctxt->context->node->type) {
5365 case XML_ELEMENT_NODE:
5366 case XML_TEXT_NODE:
5367 case XML_CDATA_SECTION_NODE:
5368 case XML_ENTITY_REF_NODE:
5369 case XML_ENTITY_NODE:
5370 case XML_PI_NODE:
5371 case XML_COMMENT_NODE:
5372 case XML_DTD_NODE:
5373 case XML_ELEMENT_DECL:
5374 case XML_ATTRIBUTE_DECL:
5375 case XML_ENTITY_DECL:
5376 case XML_NOTATION_NODE:
5377 case XML_XINCLUDE_START:
5378 case XML_XINCLUDE_END:
5379 if (ctxt->context->node->parent == NULL)
5380 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005381 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005382 ((ctxt->context->node->parent->name[0] == ' ') ||
5383 (xmlStrEqual(ctxt->context->node->parent->name,
5384 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005385 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005386 return(ctxt->context->node->parent);
5387 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005388 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005389
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005390 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005391 }
5392 case XML_DOCUMENT_NODE:
5393 case XML_DOCUMENT_TYPE_NODE:
5394 case XML_DOCUMENT_FRAG_NODE:
5395 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005396#ifdef LIBXML_DOCB_ENABLED
5397 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005398#endif
5399 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005400 case XML_NAMESPACE_DECL: {
5401 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5402
5403 if ((ns->next != NULL) &&
5404 (ns->next->type != XML_NAMESPACE_DECL))
5405 return((xmlNodePtr) ns->next);
5406 /* Bad, how did that namespace ended-up there ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005407 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005408 }
Owen Taylor3473f882001-02-23 17:55:21 +00005409 }
5410 return(NULL);
5411 }
5412 if (cur == ctxt->context->doc->children)
5413 return((xmlNodePtr) ctxt->context->doc);
5414 if (cur == (xmlNodePtr) ctxt->context->doc)
5415 return(NULL);
5416 switch (cur->type) {
5417 case XML_ELEMENT_NODE:
5418 case XML_TEXT_NODE:
5419 case XML_CDATA_SECTION_NODE:
5420 case XML_ENTITY_REF_NODE:
5421 case XML_ENTITY_NODE:
5422 case XML_PI_NODE:
5423 case XML_COMMENT_NODE:
5424 case XML_NOTATION_NODE:
5425 case XML_DTD_NODE:
5426 case XML_ELEMENT_DECL:
5427 case XML_ATTRIBUTE_DECL:
5428 case XML_ENTITY_DECL:
5429 case XML_XINCLUDE_START:
5430 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005431 if (cur->parent == NULL)
5432 return(NULL);
5433 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005434 ((cur->parent->name[0] == ' ') ||
5435 (xmlStrEqual(cur->parent->name,
5436 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005437 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005438 return(cur->parent);
5439 case XML_ATTRIBUTE_NODE: {
5440 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5441
5442 return(att->parent);
5443 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005444 case XML_NAMESPACE_DECL: {
5445 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5446
5447 if ((ns->next != NULL) &&
5448 (ns->next->type != XML_NAMESPACE_DECL))
5449 return((xmlNodePtr) ns->next);
5450 /* Bad, how did that namespace ended-up there ? */
5451 return(NULL);
5452 }
Owen Taylor3473f882001-02-23 17:55:21 +00005453 case XML_DOCUMENT_NODE:
5454 case XML_DOCUMENT_TYPE_NODE:
5455 case XML_DOCUMENT_FRAG_NODE:
5456 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005457#ifdef LIBXML_DOCB_ENABLED
5458 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005459#endif
5460 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005461 }
5462 return(NULL);
5463}
5464
5465/**
5466 * xmlXPathNextAncestorOrSelf:
5467 * @ctxt: the XPath Parser context
5468 * @cur: the current node in the traversal
5469 *
5470 * Traversal function for the "ancestor-or-self" direction
5471 * he ancestor-or-self axis contains the context node and ancestors of
5472 * the context node in reverse document order; thus the context node is
5473 * the first node on the axis, and the context node's parent the second;
5474 * parent here is defined the same as with the parent axis.
5475 *
5476 * Returns the next element following that axis
5477 */
5478xmlNodePtr
5479xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5480 if (cur == NULL)
5481 return(ctxt->context->node);
5482 return(xmlXPathNextAncestor(ctxt, cur));
5483}
5484
5485/**
5486 * xmlXPathNextFollowingSibling:
5487 * @ctxt: the XPath Parser context
5488 * @cur: the current node in the traversal
5489 *
5490 * Traversal function for the "following-sibling" direction
5491 * The following-sibling axis contains the following siblings of the context
5492 * node in document order.
5493 *
5494 * Returns the next element following that axis
5495 */
5496xmlNodePtr
5497xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5498 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5499 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5500 return(NULL);
5501 if (cur == (xmlNodePtr) ctxt->context->doc)
5502 return(NULL);
5503 if (cur == NULL)
5504 return(ctxt->context->node->next);
5505 return(cur->next);
5506}
5507
5508/**
5509 * xmlXPathNextPrecedingSibling:
5510 * @ctxt: the XPath Parser context
5511 * @cur: the current node in the traversal
5512 *
5513 * Traversal function for the "preceding-sibling" direction
5514 * The preceding-sibling axis contains the preceding siblings of the context
5515 * node in reverse document order; the first preceding sibling is first on the
5516 * axis; the sibling preceding that node is the second on the axis and so on.
5517 *
5518 * Returns the next element following that axis
5519 */
5520xmlNodePtr
5521xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5522 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5523 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5524 return(NULL);
5525 if (cur == (xmlNodePtr) ctxt->context->doc)
5526 return(NULL);
5527 if (cur == NULL)
5528 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005529 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5530 cur = cur->prev;
5531 if (cur == NULL)
5532 return(ctxt->context->node->prev);
5533 }
Owen Taylor3473f882001-02-23 17:55:21 +00005534 return(cur->prev);
5535}
5536
5537/**
5538 * xmlXPathNextFollowing:
5539 * @ctxt: the XPath Parser context
5540 * @cur: the current node in the traversal
5541 *
5542 * Traversal function for the "following" direction
5543 * The following axis contains all nodes in the same document as the context
5544 * node that are after the context node in document order, excluding any
5545 * descendants and excluding attribute nodes and namespace nodes; the nodes
5546 * are ordered in document order
5547 *
5548 * Returns the next element following that axis
5549 */
5550xmlNodePtr
5551xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5552 if (cur != NULL && cur->children != NULL)
5553 return cur->children ;
5554 if (cur == NULL) cur = ctxt->context->node;
5555 if (cur == NULL) return(NULL) ; /* ERROR */
5556 if (cur->next != NULL) return(cur->next) ;
5557 do {
5558 cur = cur->parent;
5559 if (cur == NULL) return(NULL);
5560 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5561 if (cur->next != NULL) return(cur->next);
5562 } while (cur != NULL);
5563 return(cur);
5564}
5565
5566/*
5567 * xmlXPathIsAncestor:
5568 * @ancestor: the ancestor node
5569 * @node: the current node
5570 *
5571 * Check that @ancestor is a @node's ancestor
5572 *
5573 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5574 */
5575static int
5576xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5577 if ((ancestor == NULL) || (node == NULL)) return(0);
5578 /* nodes need to be in the same document */
5579 if (ancestor->doc != node->doc) return(0);
5580 /* avoid searching if ancestor or node is the root node */
5581 if (ancestor == (xmlNodePtr) node->doc) return(1);
5582 if (node == (xmlNodePtr) ancestor->doc) return(0);
5583 while (node->parent != NULL) {
5584 if (node->parent == ancestor)
5585 return(1);
5586 node = node->parent;
5587 }
5588 return(0);
5589}
5590
5591/**
5592 * xmlXPathNextPreceding:
5593 * @ctxt: the XPath Parser context
5594 * @cur: the current node in the traversal
5595 *
5596 * Traversal function for the "preceding" direction
5597 * the preceding axis contains all nodes in the same document as the context
5598 * node that are before the context node in document order, excluding any
5599 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5600 * ordered in reverse document order
5601 *
5602 * Returns the next element following that axis
5603 */
5604xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005605xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5606{
Owen Taylor3473f882001-02-23 17:55:21 +00005607 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005608 cur = ctxt->context->node;
5609 if (cur == NULL)
5610 return (NULL);
5611 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5612 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005613 do {
5614 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005615 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5616 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005617 }
5618
5619 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005620 if (cur == NULL)
5621 return (NULL);
5622 if (cur == ctxt->context->doc->children)
5623 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005624 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005625 return (cur);
5626}
5627
5628/**
5629 * xmlXPathNextPrecedingInternal:
5630 * @ctxt: the XPath Parser context
5631 * @cur: the current node in the traversal
5632 *
5633 * Traversal function for the "preceding" direction
5634 * the preceding axis contains all nodes in the same document as the context
5635 * node that are before the context node in document order, excluding any
5636 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5637 * ordered in reverse document order
5638 * This is a faster implementation but internal only since it requires a
5639 * state kept in the parser context: ctxt->ancestor.
5640 *
5641 * Returns the next element following that axis
5642 */
5643static xmlNodePtr
5644xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5645 xmlNodePtr cur)
5646{
5647 if (cur == NULL) {
5648 cur = ctxt->context->node;
5649 if (cur == NULL)
5650 return (NULL);
5651 ctxt->ancestor = cur->parent;
5652 }
5653 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5654 cur = cur->prev;
5655 while (cur->prev == NULL) {
5656 cur = cur->parent;
5657 if (cur == NULL)
5658 return (NULL);
5659 if (cur == ctxt->context->doc->children)
5660 return (NULL);
5661 if (cur != ctxt->ancestor)
5662 return (cur);
5663 ctxt->ancestor = cur->parent;
5664 }
5665 cur = cur->prev;
5666 while (cur->last != NULL)
5667 cur = cur->last;
5668 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005669}
5670
5671/**
5672 * xmlXPathNextNamespace:
5673 * @ctxt: the XPath Parser context
5674 * @cur: the current attribute in the traversal
5675 *
5676 * Traversal function for the "namespace" direction
5677 * the namespace axis contains the namespace nodes of the context node;
5678 * the order of nodes on this axis is implementation-defined; the axis will
5679 * be empty unless the context node is an element
5680 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005681 * We keep the XML namespace node at the end of the list.
5682 *
Owen Taylor3473f882001-02-23 17:55:21 +00005683 * Returns the next element following that axis
5684 */
5685xmlNodePtr
5686xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5687 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00005688 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005689 if (ctxt->context->tmpNsList != NULL)
5690 xmlFree(ctxt->context->tmpNsList);
5691 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005692 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005693 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005694 if (ctxt->context->tmpNsList != NULL) {
5695 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
5696 ctxt->context->tmpNsNr++;
5697 }
5698 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005699 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005700 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00005701 if (ctxt->context->tmpNsNr > 0) {
5702 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
5703 } else {
5704 if (ctxt->context->tmpNsList != NULL)
5705 xmlFree(ctxt->context->tmpNsList);
5706 ctxt->context->tmpNsList = NULL;
5707 return(NULL);
5708 }
Owen Taylor3473f882001-02-23 17:55:21 +00005709}
5710
5711/**
5712 * xmlXPathNextAttribute:
5713 * @ctxt: the XPath Parser context
5714 * @cur: the current attribute in the traversal
5715 *
5716 * Traversal function for the "attribute" direction
5717 * TODO: support DTD inherited default attributes
5718 *
5719 * Returns the next element following that axis
5720 */
5721xmlNodePtr
5722xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005723 if (ctxt->context->node == NULL)
5724 return(NULL);
5725 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5726 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005727 if (cur == NULL) {
5728 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5729 return(NULL);
5730 return((xmlNodePtr)ctxt->context->node->properties);
5731 }
5732 return((xmlNodePtr)cur->next);
5733}
5734
5735/************************************************************************
5736 * *
5737 * NodeTest Functions *
5738 * *
5739 ************************************************************************/
5740
Owen Taylor3473f882001-02-23 17:55:21 +00005741#define IS_FUNCTION 200
5742
Owen Taylor3473f882001-02-23 17:55:21 +00005743
5744/************************************************************************
5745 * *
5746 * Implicit tree core function library *
5747 * *
5748 ************************************************************************/
5749
5750/**
5751 * xmlXPathRoot:
5752 * @ctxt: the XPath Parser context
5753 *
5754 * Initialize the context to the root of the document
5755 */
5756void
5757xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5758 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5759 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5760}
5761
5762/************************************************************************
5763 * *
5764 * The explicit core function library *
5765 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5766 * *
5767 ************************************************************************/
5768
5769
5770/**
5771 * xmlXPathLastFunction:
5772 * @ctxt: the XPath Parser context
5773 * @nargs: the number of arguments
5774 *
5775 * Implement the last() XPath function
5776 * number last()
5777 * The last function returns the number of nodes in the context node list.
5778 */
5779void
5780xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5781 CHECK_ARITY(0);
5782 if (ctxt->context->contextSize >= 0) {
5783 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5784#ifdef DEBUG_EXPR
5785 xmlGenericError(xmlGenericErrorContext,
5786 "last() : %d\n", ctxt->context->contextSize);
5787#endif
5788 } else {
5789 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5790 }
5791}
5792
5793/**
5794 * xmlXPathPositionFunction:
5795 * @ctxt: the XPath Parser context
5796 * @nargs: the number of arguments
5797 *
5798 * Implement the position() XPath function
5799 * number position()
5800 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005801 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00005802 * will be equal to last().
5803 */
5804void
5805xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5806 CHECK_ARITY(0);
5807 if (ctxt->context->proximityPosition >= 0) {
5808 valuePush(ctxt,
5809 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5810#ifdef DEBUG_EXPR
5811 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5812 ctxt->context->proximityPosition);
5813#endif
5814 } else {
5815 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5816 }
5817}
5818
5819/**
5820 * xmlXPathCountFunction:
5821 * @ctxt: the XPath Parser context
5822 * @nargs: the number of arguments
5823 *
5824 * Implement the count() XPath function
5825 * number count(node-set)
5826 */
5827void
5828xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5829 xmlXPathObjectPtr cur;
5830
5831 CHECK_ARITY(1);
5832 if ((ctxt->value == NULL) ||
5833 ((ctxt->value->type != XPATH_NODESET) &&
5834 (ctxt->value->type != XPATH_XSLT_TREE)))
5835 XP_ERROR(XPATH_INVALID_TYPE);
5836 cur = valuePop(ctxt);
5837
Daniel Veillard911f49a2001-04-07 15:39:35 +00005838 if ((cur == NULL) || (cur->nodesetval == NULL))
5839 valuePush(ctxt, xmlXPathNewFloat((double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00005840 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00005841 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00005842 } else {
5843 if ((cur->nodesetval->nodeNr != 1) ||
5844 (cur->nodesetval->nodeTab == NULL)) {
5845 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5846 } else {
5847 xmlNodePtr tmp;
5848 int i = 0;
5849
5850 tmp = cur->nodesetval->nodeTab[0];
5851 if (tmp != NULL) {
5852 tmp = tmp->children;
5853 while (tmp != NULL) {
5854 tmp = tmp->next;
5855 i++;
5856 }
5857 }
5858 valuePush(ctxt, xmlXPathNewFloat((double) i));
5859 }
5860 }
Owen Taylor3473f882001-02-23 17:55:21 +00005861 xmlXPathFreeObject(cur);
5862}
5863
5864/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005865 * xmlXPathGetElementsByIds:
5866 * @doc: the document
5867 * @ids: a whitespace separated list of IDs
5868 *
5869 * Selects elements by their unique ID.
5870 *
5871 * Returns a node-set of selected elements.
5872 */
5873static xmlNodeSetPtr
5874xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5875 xmlNodeSetPtr ret;
5876 const xmlChar *cur = ids;
5877 xmlChar *ID;
5878 xmlAttrPtr attr;
5879 xmlNodePtr elem = NULL;
5880
5881 ret = xmlXPathNodeSetCreate(NULL);
5882
5883 while (IS_BLANK(*cur)) cur++;
5884 while (*cur != 0) {
5885 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
5886 (*cur == '.') || (*cur == '-') ||
5887 (*cur == '_') || (*cur == ':') ||
5888 (IS_COMBINING(*cur)) ||
5889 (IS_EXTENDER(*cur)))
5890 cur++;
5891
5892 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
5893
5894 ID = xmlStrndup(ids, cur - ids);
5895 attr = xmlGetID(doc, ID);
5896 if (attr != NULL) {
5897 elem = attr->parent;
5898 xmlXPathNodeSetAdd(ret, elem);
5899 }
5900 if (ID != NULL)
5901 xmlFree(ID);
5902
5903 while (IS_BLANK(*cur)) cur++;
5904 ids = cur;
5905 }
5906 return(ret);
5907}
5908
5909/**
Owen Taylor3473f882001-02-23 17:55:21 +00005910 * xmlXPathIdFunction:
5911 * @ctxt: the XPath Parser context
5912 * @nargs: the number of arguments
5913 *
5914 * Implement the id() XPath function
5915 * node-set id(object)
5916 * The id function selects elements by their unique ID
5917 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
5918 * then the result is the union of the result of applying id to the
5919 * string value of each of the nodes in the argument node-set. When the
5920 * argument to id is of any other type, the argument is converted to a
5921 * string as if by a call to the string function; the string is split
5922 * into a whitespace-separated list of tokens (whitespace is any sequence
5923 * of characters matching the production S); the result is a node-set
5924 * containing the elements in the same document as the context node that
5925 * have a unique ID equal to any of the tokens in the list.
5926 */
5927void
5928xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005929 xmlChar *tokens;
5930 xmlNodeSetPtr ret;
5931 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00005932
5933 CHECK_ARITY(1);
5934 obj = valuePop(ctxt);
5935 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00005936 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005937 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00005938 int i;
5939
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005940 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005941
Daniel Veillard911f49a2001-04-07 15:39:35 +00005942 if (obj->nodesetval != NULL) {
5943 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005944 tokens =
5945 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
5946 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
5947 ret = xmlXPathNodeSetMerge(ret, ns);
5948 xmlXPathFreeNodeSet(ns);
5949 if (tokens != NULL)
5950 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00005951 }
Owen Taylor3473f882001-02-23 17:55:21 +00005952 }
5953
5954 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005955 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005956 return;
5957 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005958 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00005959
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005960 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
5961 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005962
Owen Taylor3473f882001-02-23 17:55:21 +00005963 xmlXPathFreeObject(obj);
5964 return;
5965}
5966
5967/**
5968 * xmlXPathLocalNameFunction:
5969 * @ctxt: the XPath Parser context
5970 * @nargs: the number of arguments
5971 *
5972 * Implement the local-name() XPath function
5973 * string local-name(node-set?)
5974 * The local-name function returns a string containing the local part
5975 * of the name of the node in the argument node-set that is first in
5976 * document order. If the node-set is empty or the first node has no
5977 * name, an empty string is returned. If the argument is omitted it
5978 * defaults to the context node.
5979 */
5980void
5981xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5982 xmlXPathObjectPtr cur;
5983
5984 if (nargs == 0) {
5985 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5986 nargs = 1;
5987 }
5988
5989 CHECK_ARITY(1);
5990 if ((ctxt->value == NULL) ||
5991 ((ctxt->value->type != XPATH_NODESET) &&
5992 (ctxt->value->type != XPATH_XSLT_TREE)))
5993 XP_ERROR(XPATH_INVALID_TYPE);
5994 cur = valuePop(ctxt);
5995
Daniel Veillard911f49a2001-04-07 15:39:35 +00005996 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005997 valuePush(ctxt, xmlXPathNewCString(""));
5998 } else {
5999 int i = 0; /* Should be first in document order !!!!! */
6000 switch (cur->nodesetval->nodeTab[i]->type) {
6001 case XML_ELEMENT_NODE:
6002 case XML_ATTRIBUTE_NODE:
6003 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006004 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6005 valuePush(ctxt, xmlXPathNewCString(""));
6006 else
6007 valuePush(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006008 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
6009 break;
6010 case XML_NAMESPACE_DECL:
6011 valuePush(ctxt, xmlXPathNewString(
6012 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
6013 break;
6014 default:
6015 valuePush(ctxt, xmlXPathNewCString(""));
6016 }
6017 }
6018 xmlXPathFreeObject(cur);
6019}
6020
6021/**
6022 * xmlXPathNamespaceURIFunction:
6023 * @ctxt: the XPath Parser context
6024 * @nargs: the number of arguments
6025 *
6026 * Implement the namespace-uri() XPath function
6027 * string namespace-uri(node-set?)
6028 * The namespace-uri function returns a string containing the
6029 * namespace URI of the expanded name of the node in the argument
6030 * node-set that is first in document order. If the node-set is empty,
6031 * the first node has no name, or the expanded name has no namespace
6032 * URI, an empty string is returned. If the argument is omitted it
6033 * defaults to the context node.
6034 */
6035void
6036xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6037 xmlXPathObjectPtr cur;
6038
6039 if (nargs == 0) {
6040 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6041 nargs = 1;
6042 }
6043 CHECK_ARITY(1);
6044 if ((ctxt->value == NULL) ||
6045 ((ctxt->value->type != XPATH_NODESET) &&
6046 (ctxt->value->type != XPATH_XSLT_TREE)))
6047 XP_ERROR(XPATH_INVALID_TYPE);
6048 cur = valuePop(ctxt);
6049
Daniel Veillard911f49a2001-04-07 15:39:35 +00006050 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006051 valuePush(ctxt, xmlXPathNewCString(""));
6052 } else {
6053 int i = 0; /* Should be first in document order !!!!! */
6054 switch (cur->nodesetval->nodeTab[i]->type) {
6055 case XML_ELEMENT_NODE:
6056 case XML_ATTRIBUTE_NODE:
6057 if (cur->nodesetval->nodeTab[i]->ns == NULL)
6058 valuePush(ctxt, xmlXPathNewCString(""));
6059 else
6060 valuePush(ctxt, xmlXPathNewString(
6061 cur->nodesetval->nodeTab[i]->ns->href));
6062 break;
6063 default:
6064 valuePush(ctxt, xmlXPathNewCString(""));
6065 }
6066 }
6067 xmlXPathFreeObject(cur);
6068}
6069
6070/**
6071 * xmlXPathNameFunction:
6072 * @ctxt: the XPath Parser context
6073 * @nargs: the number of arguments
6074 *
6075 * Implement the name() XPath function
6076 * string name(node-set?)
6077 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006078 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00006079 * order. The QName must represent the name with respect to the namespace
6080 * declarations in effect on the node whose name is being represented.
6081 * Typically, this will be the form in which the name occurred in the XML
6082 * source. This need not be the case if there are namespace declarations
6083 * in effect on the node that associate multiple prefixes with the same
6084 * namespace. However, an implementation may include information about
6085 * the original prefix in its representation of nodes; in this case, an
6086 * implementation can ensure that the returned string is always the same
6087 * as the QName used in the XML source. If the argument it omitted it
6088 * defaults to the context node.
6089 * Libxml keep the original prefix so the "real qualified name" used is
6090 * returned.
6091 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006092static void
Daniel Veillard04383752001-07-08 14:27:15 +00006093xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
6094{
Owen Taylor3473f882001-02-23 17:55:21 +00006095 xmlXPathObjectPtr cur;
6096
6097 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00006098 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6099 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006100 }
6101
6102 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00006103 if ((ctxt->value == NULL) ||
6104 ((ctxt->value->type != XPATH_NODESET) &&
6105 (ctxt->value->type != XPATH_XSLT_TREE)))
6106 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006107 cur = valuePop(ctxt);
6108
Daniel Veillard911f49a2001-04-07 15:39:35 +00006109 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006110 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00006111 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006112 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00006113
Daniel Veillard04383752001-07-08 14:27:15 +00006114 switch (cur->nodesetval->nodeTab[i]->type) {
6115 case XML_ELEMENT_NODE:
6116 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006117 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6118 valuePush(ctxt, xmlXPathNewCString(""));
6119 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6120 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006121 valuePush(ctxt,
6122 xmlXPathNewString(cur->nodesetval->
6123 nodeTab[i]->name));
6124
Daniel Veillard652d8a92003-02-04 19:28:49 +00006125 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006126 char name[2000];
6127
6128 snprintf(name, sizeof(name), "%s:%s",
6129 (char *) cur->nodesetval->nodeTab[i]->ns->
6130 prefix,
6131 (char *) cur->nodesetval->nodeTab[i]->name);
6132 name[sizeof(name) - 1] = 0;
6133 valuePush(ctxt, xmlXPathNewCString(name));
6134 }
6135 break;
6136 default:
6137 valuePush(ctxt,
6138 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6139 xmlXPathLocalNameFunction(ctxt, 1);
6140 }
Owen Taylor3473f882001-02-23 17:55:21 +00006141 }
6142 xmlXPathFreeObject(cur);
6143}
6144
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006145
6146/**
Owen Taylor3473f882001-02-23 17:55:21 +00006147 * xmlXPathStringFunction:
6148 * @ctxt: the XPath Parser context
6149 * @nargs: the number of arguments
6150 *
6151 * Implement the string() XPath function
6152 * string string(object?)
6153 * he string function converts an object to a string as follows:
6154 * - A node-set is converted to a string by returning the value of
6155 * the node in the node-set that is first in document order.
6156 * If the node-set is empty, an empty string is returned.
6157 * - A number is converted to a string as follows
6158 * + NaN is converted to the string NaN
6159 * + positive zero is converted to the string 0
6160 * + negative zero is converted to the string 0
6161 * + positive infinity is converted to the string Infinity
6162 * + negative infinity is converted to the string -Infinity
6163 * + if the number is an integer, the number is represented in
6164 * decimal form as a Number with no decimal point and no leading
6165 * zeros, preceded by a minus sign (-) if the number is negative
6166 * + otherwise, the number is represented in decimal form as a
6167 * Number including a decimal point with at least one digit
6168 * before the decimal point and at least one digit after the
6169 * decimal point, preceded by a minus sign (-) if the number
6170 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006171 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00006172 * before the decimal point; beyond the one required digit
6173 * after the decimal point there must be as many, but only as
6174 * many, more digits as are needed to uniquely distinguish the
6175 * number from all other IEEE 754 numeric values.
6176 * - The boolean false value is converted to the string false.
6177 * The boolean true value is converted to the string true.
6178 *
6179 * If the argument is omitted, it defaults to a node-set with the
6180 * context node as its only member.
6181 */
6182void
6183xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6184 xmlXPathObjectPtr cur;
6185
6186 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006187 valuePush(ctxt,
6188 xmlXPathWrapString(
6189 xmlXPathCastNodeToString(ctxt->context->node)));
6190 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006191 }
6192
6193 CHECK_ARITY(1);
6194 cur = valuePop(ctxt);
6195 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006196 cur = xmlXPathConvertString(cur);
6197 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006198}
6199
6200/**
6201 * xmlXPathStringLengthFunction:
6202 * @ctxt: the XPath Parser context
6203 * @nargs: the number of arguments
6204 *
6205 * Implement the string-length() XPath function
6206 * number string-length(string?)
6207 * The string-length returns the number of characters in the string
6208 * (see [3.6 Strings]). If the argument is omitted, it defaults to
6209 * the context node converted to a string, in other words the value
6210 * of the context node.
6211 */
6212void
6213xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6214 xmlXPathObjectPtr cur;
6215
6216 if (nargs == 0) {
6217 if (ctxt->context->node == NULL) {
6218 valuePush(ctxt, xmlXPathNewFloat(0));
6219 } else {
6220 xmlChar *content;
6221
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006222 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006223 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00006224 xmlFree(content);
6225 }
6226 return;
6227 }
6228 CHECK_ARITY(1);
6229 CAST_TO_STRING;
6230 CHECK_TYPE(XPATH_STRING);
6231 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006232 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00006233 xmlXPathFreeObject(cur);
6234}
6235
6236/**
6237 * xmlXPathConcatFunction:
6238 * @ctxt: the XPath Parser context
6239 * @nargs: the number of arguments
6240 *
6241 * Implement the concat() XPath function
6242 * string concat(string, string, string*)
6243 * The concat function returns the concatenation of its arguments.
6244 */
6245void
6246xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6247 xmlXPathObjectPtr cur, newobj;
6248 xmlChar *tmp;
6249
6250 if (nargs < 2) {
6251 CHECK_ARITY(2);
6252 }
6253
6254 CAST_TO_STRING;
6255 cur = valuePop(ctxt);
6256 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6257 xmlXPathFreeObject(cur);
6258 return;
6259 }
6260 nargs--;
6261
6262 while (nargs > 0) {
6263 CAST_TO_STRING;
6264 newobj = valuePop(ctxt);
6265 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6266 xmlXPathFreeObject(newobj);
6267 xmlXPathFreeObject(cur);
6268 XP_ERROR(XPATH_INVALID_TYPE);
6269 }
6270 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6271 newobj->stringval = cur->stringval;
6272 cur->stringval = tmp;
6273
6274 xmlXPathFreeObject(newobj);
6275 nargs--;
6276 }
6277 valuePush(ctxt, cur);
6278}
6279
6280/**
6281 * xmlXPathContainsFunction:
6282 * @ctxt: the XPath Parser context
6283 * @nargs: the number of arguments
6284 *
6285 * Implement the contains() XPath function
6286 * boolean contains(string, string)
6287 * The contains function returns true if the first argument string
6288 * contains the second argument string, and otherwise returns false.
6289 */
6290void
6291xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6292 xmlXPathObjectPtr hay, needle;
6293
6294 CHECK_ARITY(2);
6295 CAST_TO_STRING;
6296 CHECK_TYPE(XPATH_STRING);
6297 needle = valuePop(ctxt);
6298 CAST_TO_STRING;
6299 hay = valuePop(ctxt);
6300 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6301 xmlXPathFreeObject(hay);
6302 xmlXPathFreeObject(needle);
6303 XP_ERROR(XPATH_INVALID_TYPE);
6304 }
6305 if (xmlStrstr(hay->stringval, needle->stringval))
6306 valuePush(ctxt, xmlXPathNewBoolean(1));
6307 else
6308 valuePush(ctxt, xmlXPathNewBoolean(0));
6309 xmlXPathFreeObject(hay);
6310 xmlXPathFreeObject(needle);
6311}
6312
6313/**
6314 * xmlXPathStartsWithFunction:
6315 * @ctxt: the XPath Parser context
6316 * @nargs: the number of arguments
6317 *
6318 * Implement the starts-with() XPath function
6319 * boolean starts-with(string, string)
6320 * The starts-with function returns true if the first argument string
6321 * starts with the second argument string, and otherwise returns false.
6322 */
6323void
6324xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6325 xmlXPathObjectPtr hay, needle;
6326 int n;
6327
6328 CHECK_ARITY(2);
6329 CAST_TO_STRING;
6330 CHECK_TYPE(XPATH_STRING);
6331 needle = valuePop(ctxt);
6332 CAST_TO_STRING;
6333 hay = valuePop(ctxt);
6334 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6335 xmlXPathFreeObject(hay);
6336 xmlXPathFreeObject(needle);
6337 XP_ERROR(XPATH_INVALID_TYPE);
6338 }
6339 n = xmlStrlen(needle->stringval);
6340 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6341 valuePush(ctxt, xmlXPathNewBoolean(0));
6342 else
6343 valuePush(ctxt, xmlXPathNewBoolean(1));
6344 xmlXPathFreeObject(hay);
6345 xmlXPathFreeObject(needle);
6346}
6347
6348/**
6349 * xmlXPathSubstringFunction:
6350 * @ctxt: the XPath Parser context
6351 * @nargs: the number of arguments
6352 *
6353 * Implement the substring() XPath function
6354 * string substring(string, number, number?)
6355 * The substring function returns the substring of the first argument
6356 * starting at the position specified in the second argument with
6357 * length specified in the third argument. For example,
6358 * substring("12345",2,3) returns "234". If the third argument is not
6359 * specified, it returns the substring starting at the position specified
6360 * in the second argument and continuing to the end of the string. For
6361 * example, substring("12345",2) returns "2345". More precisely, each
6362 * character in the string (see [3.6 Strings]) is considered to have a
6363 * numeric position: the position of the first character is 1, the position
6364 * of the second character is 2 and so on. The returned substring contains
6365 * those characters for which the position of the character is greater than
6366 * or equal to the second argument and, if the third argument is specified,
6367 * less than the sum of the second and third arguments; the comparisons
6368 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6369 * - substring("12345", 1.5, 2.6) returns "234"
6370 * - substring("12345", 0, 3) returns "12"
6371 * - substring("12345", 0 div 0, 3) returns ""
6372 * - substring("12345", 1, 0 div 0) returns ""
6373 * - substring("12345", -42, 1 div 0) returns "12345"
6374 * - substring("12345", -1 div 0, 1 div 0) returns ""
6375 */
6376void
6377xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6378 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006379 double le=0, in;
6380 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006381 xmlChar *ret;
6382
Owen Taylor3473f882001-02-23 17:55:21 +00006383 if (nargs < 2) {
6384 CHECK_ARITY(2);
6385 }
6386 if (nargs > 3) {
6387 CHECK_ARITY(3);
6388 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006389 /*
6390 * take care of possible last (position) argument
6391 */
Owen Taylor3473f882001-02-23 17:55:21 +00006392 if (nargs == 3) {
6393 CAST_TO_NUMBER;
6394 CHECK_TYPE(XPATH_NUMBER);
6395 len = valuePop(ctxt);
6396 le = len->floatval;
6397 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006398 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006399
Owen Taylor3473f882001-02-23 17:55:21 +00006400 CAST_TO_NUMBER;
6401 CHECK_TYPE(XPATH_NUMBER);
6402 start = valuePop(ctxt);
6403 in = start->floatval;
6404 xmlXPathFreeObject(start);
6405 CAST_TO_STRING;
6406 CHECK_TYPE(XPATH_STRING);
6407 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006408 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006409
Daniel Veillard97ac1312001-05-30 19:14:17 +00006410 /*
6411 * If last pos not present, calculate last position
6412 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006413 if (nargs != 3) {
6414 le = (double)m;
6415 if (in < 1.0)
6416 in = 1.0;
6417 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006418
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006419 /* Need to check for the special cases where either
6420 * the index is NaN, the length is NaN, or both
6421 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00006422 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006423 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006424 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00006425 * To meet the requirements of the spec, the arguments
6426 * must be converted to integer format before
6427 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006428 *
Daniel Veillard9e412302002-06-10 15:59:44 +00006429 * First we go to integer form, rounding up
6430 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006431 */
6432 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00006433 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00006434
Daniel Veillard9e412302002-06-10 15:59:44 +00006435 if (xmlXPathIsInf(le) == 1) {
6436 l = m;
6437 if (i < 1)
6438 i = 1;
6439 }
6440 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
6441 l = 0;
6442 else {
6443 l = (int) le;
6444 if (((double)l)+0.5 <= le) l++;
6445 }
6446
6447 /* Now we normalize inidices */
6448 i -= 1;
6449 l += i;
6450 if (i < 0)
6451 i = 0;
6452 if (l > m)
6453 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00006454
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006455 /* number of chars to copy */
6456 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00006457
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006458 ret = xmlUTF8Strsub(str->stringval, i, l);
6459 }
6460 else {
6461 ret = NULL;
6462 }
6463
Owen Taylor3473f882001-02-23 17:55:21 +00006464 if (ret == NULL)
6465 valuePush(ctxt, xmlXPathNewCString(""));
6466 else {
6467 valuePush(ctxt, xmlXPathNewString(ret));
6468 xmlFree(ret);
6469 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006470
Owen Taylor3473f882001-02-23 17:55:21 +00006471 xmlXPathFreeObject(str);
6472}
6473
6474/**
6475 * xmlXPathSubstringBeforeFunction:
6476 * @ctxt: the XPath Parser context
6477 * @nargs: the number of arguments
6478 *
6479 * Implement the substring-before() XPath function
6480 * string substring-before(string, string)
6481 * The substring-before function returns the substring of the first
6482 * argument string that precedes the first occurrence of the second
6483 * argument string in the first argument string, or the empty string
6484 * if the first argument string does not contain the second argument
6485 * string. For example, substring-before("1999/04/01","/") returns 1999.
6486 */
6487void
6488xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6489 xmlXPathObjectPtr str;
6490 xmlXPathObjectPtr find;
6491 xmlBufferPtr target;
6492 const xmlChar *point;
6493 int offset;
6494
6495 CHECK_ARITY(2);
6496 CAST_TO_STRING;
6497 find = valuePop(ctxt);
6498 CAST_TO_STRING;
6499 str = valuePop(ctxt);
6500
6501 target = xmlBufferCreate();
6502 if (target) {
6503 point = xmlStrstr(str->stringval, find->stringval);
6504 if (point) {
6505 offset = (int)(point - str->stringval);
6506 xmlBufferAdd(target, str->stringval, offset);
6507 }
6508 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6509 xmlBufferFree(target);
6510 }
6511
6512 xmlXPathFreeObject(str);
6513 xmlXPathFreeObject(find);
6514}
6515
6516/**
6517 * xmlXPathSubstringAfterFunction:
6518 * @ctxt: the XPath Parser context
6519 * @nargs: the number of arguments
6520 *
6521 * Implement the substring-after() XPath function
6522 * string substring-after(string, string)
6523 * The substring-after function returns the substring of the first
6524 * argument string that follows the first occurrence of the second
6525 * argument string in the first argument string, or the empty stringi
6526 * if the first argument string does not contain the second argument
6527 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6528 * and substring-after("1999/04/01","19") returns 99/04/01.
6529 */
6530void
6531xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6532 xmlXPathObjectPtr str;
6533 xmlXPathObjectPtr find;
6534 xmlBufferPtr target;
6535 const xmlChar *point;
6536 int offset;
6537
6538 CHECK_ARITY(2);
6539 CAST_TO_STRING;
6540 find = valuePop(ctxt);
6541 CAST_TO_STRING;
6542 str = valuePop(ctxt);
6543
6544 target = xmlBufferCreate();
6545 if (target) {
6546 point = xmlStrstr(str->stringval, find->stringval);
6547 if (point) {
6548 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6549 xmlBufferAdd(target, &str->stringval[offset],
6550 xmlStrlen(str->stringval) - offset);
6551 }
6552 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6553 xmlBufferFree(target);
6554 }
6555
6556 xmlXPathFreeObject(str);
6557 xmlXPathFreeObject(find);
6558}
6559
6560/**
6561 * xmlXPathNormalizeFunction:
6562 * @ctxt: the XPath Parser context
6563 * @nargs: the number of arguments
6564 *
6565 * Implement the normalize-space() XPath function
6566 * string normalize-space(string?)
6567 * The normalize-space function returns the argument string with white
6568 * space normalized by stripping leading and trailing whitespace
6569 * and replacing sequences of whitespace characters by a single
6570 * space. Whitespace characters are the same allowed by the S production
6571 * in XML. If the argument is omitted, it defaults to the context
6572 * node converted to a string, in other words the value of the context node.
6573 */
6574void
6575xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6576 xmlXPathObjectPtr obj = NULL;
6577 xmlChar *source = NULL;
6578 xmlBufferPtr target;
6579 xmlChar blank;
6580
6581 if (nargs == 0) {
6582 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006583 valuePush(ctxt,
6584 xmlXPathWrapString(
6585 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006586 nargs = 1;
6587 }
6588
6589 CHECK_ARITY(1);
6590 CAST_TO_STRING;
6591 CHECK_TYPE(XPATH_STRING);
6592 obj = valuePop(ctxt);
6593 source = obj->stringval;
6594
6595 target = xmlBufferCreate();
6596 if (target && source) {
6597
6598 /* Skip leading whitespaces */
6599 while (IS_BLANK(*source))
6600 source++;
6601
6602 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6603 blank = 0;
6604 while (*source) {
6605 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006606 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006607 } else {
6608 if (blank) {
6609 xmlBufferAdd(target, &blank, 1);
6610 blank = 0;
6611 }
6612 xmlBufferAdd(target, source, 1);
6613 }
6614 source++;
6615 }
6616
6617 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6618 xmlBufferFree(target);
6619 }
6620 xmlXPathFreeObject(obj);
6621}
6622
6623/**
6624 * xmlXPathTranslateFunction:
6625 * @ctxt: the XPath Parser context
6626 * @nargs: the number of arguments
6627 *
6628 * Implement the translate() XPath function
6629 * string translate(string, string, string)
6630 * The translate function returns the first argument string with
6631 * occurrences of characters in the second argument string replaced
6632 * by the character at the corresponding position in the third argument
6633 * string. For example, translate("bar","abc","ABC") returns the string
6634 * BAr. If there is a character in the second argument string with no
6635 * character at a corresponding position in the third argument string
6636 * (because the second argument string is longer than the third argument
6637 * string), then occurrences of that character in the first argument
6638 * string are removed. For example, translate("--aaa--","abc-","ABC")
6639 * returns "AAA". If a character occurs more than once in second
6640 * argument string, then the first occurrence determines the replacement
6641 * character. If the third argument string is longer than the second
6642 * argument string, then excess characters are ignored.
6643 */
6644void
6645xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006646 xmlXPathObjectPtr str;
6647 xmlXPathObjectPtr from;
6648 xmlXPathObjectPtr to;
6649 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006650 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006651 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006652 xmlChar *point;
6653 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006654
Daniel Veillarde043ee12001-04-16 14:08:07 +00006655 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006656
Daniel Veillarde043ee12001-04-16 14:08:07 +00006657 CAST_TO_STRING;
6658 to = valuePop(ctxt);
6659 CAST_TO_STRING;
6660 from = valuePop(ctxt);
6661 CAST_TO_STRING;
6662 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006663
Daniel Veillarde043ee12001-04-16 14:08:07 +00006664 target = xmlBufferCreate();
6665 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006666 max = xmlUTF8Strlen(to->stringval);
6667 for (cptr = str->stringval; (ch=*cptr); ) {
6668 offset = xmlUTF8Strloc(from->stringval, cptr);
6669 if (offset >= 0) {
6670 if (offset < max) {
6671 point = xmlUTF8Strpos(to->stringval, offset);
6672 if (point)
6673 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6674 }
6675 } else
6676 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6677
6678 /* Step to next character in input */
6679 cptr++;
6680 if ( ch & 0x80 ) {
6681 /* if not simple ascii, verify proper format */
6682 if ( (ch & 0xc0) != 0xc0 ) {
6683 xmlGenericError(xmlGenericErrorContext,
6684 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6685 break;
6686 }
6687 /* then skip over remaining bytes for this char */
6688 while ( (ch <<= 1) & 0x80 )
6689 if ( (*cptr++ & 0xc0) != 0x80 ) {
6690 xmlGenericError(xmlGenericErrorContext,
6691 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6692 break;
6693 }
6694 if (ch & 0x80) /* must have had error encountered */
6695 break;
6696 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006697 }
Owen Taylor3473f882001-02-23 17:55:21 +00006698 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006699 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6700 xmlBufferFree(target);
6701 xmlXPathFreeObject(str);
6702 xmlXPathFreeObject(from);
6703 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006704}
6705
6706/**
6707 * xmlXPathBooleanFunction:
6708 * @ctxt: the XPath Parser context
6709 * @nargs: the number of arguments
6710 *
6711 * Implement the boolean() XPath function
6712 * boolean boolean(object)
6713 * he boolean function converts its argument to a boolean as follows:
6714 * - a number is true if and only if it is neither positive or
6715 * negative zero nor NaN
6716 * - a node-set is true if and only if it is non-empty
6717 * - a string is true if and only if its length is non-zero
6718 */
6719void
6720xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6721 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006722
6723 CHECK_ARITY(1);
6724 cur = valuePop(ctxt);
6725 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006726 cur = xmlXPathConvertBoolean(cur);
6727 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006728}
6729
6730/**
6731 * xmlXPathNotFunction:
6732 * @ctxt: the XPath Parser context
6733 * @nargs: the number of arguments
6734 *
6735 * Implement the not() XPath function
6736 * boolean not(boolean)
6737 * The not function returns true if its argument is false,
6738 * and false otherwise.
6739 */
6740void
6741xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6742 CHECK_ARITY(1);
6743 CAST_TO_BOOLEAN;
6744 CHECK_TYPE(XPATH_BOOLEAN);
6745 ctxt->value->boolval = ! ctxt->value->boolval;
6746}
6747
6748/**
6749 * xmlXPathTrueFunction:
6750 * @ctxt: the XPath Parser context
6751 * @nargs: the number of arguments
6752 *
6753 * Implement the true() XPath function
6754 * boolean true()
6755 */
6756void
6757xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6758 CHECK_ARITY(0);
6759 valuePush(ctxt, xmlXPathNewBoolean(1));
6760}
6761
6762/**
6763 * xmlXPathFalseFunction:
6764 * @ctxt: the XPath Parser context
6765 * @nargs: the number of arguments
6766 *
6767 * Implement the false() XPath function
6768 * boolean false()
6769 */
6770void
6771xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6772 CHECK_ARITY(0);
6773 valuePush(ctxt, xmlXPathNewBoolean(0));
6774}
6775
6776/**
6777 * xmlXPathLangFunction:
6778 * @ctxt: the XPath Parser context
6779 * @nargs: the number of arguments
6780 *
6781 * Implement the lang() XPath function
6782 * boolean lang(string)
6783 * The lang function returns true or false depending on whether the
6784 * language of the context node as specified by xml:lang attributes
6785 * is the same as or is a sublanguage of the language specified by
6786 * the argument string. The language of the context node is determined
6787 * by the value of the xml:lang attribute on the context node, or, if
6788 * the context node has no xml:lang attribute, by the value of the
6789 * xml:lang attribute on the nearest ancestor of the context node that
6790 * has an xml:lang attribute. If there is no such attribute, then lang
6791 * returns false. If there is such an attribute, then lang returns
6792 * true if the attribute value is equal to the argument ignoring case,
6793 * or if there is some suffix starting with - such that the attribute
6794 * value is equal to the argument ignoring that suffix of the attribute
6795 * value and ignoring case.
6796 */
6797void
6798xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6799 xmlXPathObjectPtr val;
6800 const xmlChar *theLang;
6801 const xmlChar *lang;
6802 int ret = 0;
6803 int i;
6804
6805 CHECK_ARITY(1);
6806 CAST_TO_STRING;
6807 CHECK_TYPE(XPATH_STRING);
6808 val = valuePop(ctxt);
6809 lang = val->stringval;
6810 theLang = xmlNodeGetLang(ctxt->context->node);
6811 if ((theLang != NULL) && (lang != NULL)) {
6812 for (i = 0;lang[i] != 0;i++)
6813 if (toupper(lang[i]) != toupper(theLang[i]))
6814 goto not_equal;
6815 ret = 1;
6816 }
6817not_equal:
6818 xmlXPathFreeObject(val);
6819 valuePush(ctxt, xmlXPathNewBoolean(ret));
6820}
6821
6822/**
6823 * xmlXPathNumberFunction:
6824 * @ctxt: the XPath Parser context
6825 * @nargs: the number of arguments
6826 *
6827 * Implement the number() XPath function
6828 * number number(object?)
6829 */
6830void
6831xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6832 xmlXPathObjectPtr cur;
6833 double res;
6834
6835 if (nargs == 0) {
6836 if (ctxt->context->node == NULL) {
6837 valuePush(ctxt, xmlXPathNewFloat(0.0));
6838 } else {
6839 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6840
6841 res = xmlXPathStringEvalNumber(content);
6842 valuePush(ctxt, xmlXPathNewFloat(res));
6843 xmlFree(content);
6844 }
6845 return;
6846 }
6847
6848 CHECK_ARITY(1);
6849 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006850 cur = xmlXPathConvertNumber(cur);
6851 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006852}
6853
6854/**
6855 * xmlXPathSumFunction:
6856 * @ctxt: the XPath Parser context
6857 * @nargs: the number of arguments
6858 *
6859 * Implement the sum() XPath function
6860 * number sum(node-set)
6861 * The sum function returns the sum of the values of the nodes in
6862 * the argument node-set.
6863 */
6864void
6865xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6866 xmlXPathObjectPtr cur;
6867 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006868 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00006869
6870 CHECK_ARITY(1);
6871 if ((ctxt->value == NULL) ||
6872 ((ctxt->value->type != XPATH_NODESET) &&
6873 (ctxt->value->type != XPATH_XSLT_TREE)))
6874 XP_ERROR(XPATH_INVALID_TYPE);
6875 cur = valuePop(ctxt);
6876
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006877 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006878 valuePush(ctxt, xmlXPathNewFloat(0.0));
6879 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006880 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
6881 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006882 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006883 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00006884 }
6885 xmlXPathFreeObject(cur);
6886}
6887
6888/**
6889 * xmlXPathFloorFunction:
6890 * @ctxt: the XPath Parser context
6891 * @nargs: the number of arguments
6892 *
6893 * Implement the floor() XPath function
6894 * number floor(number)
6895 * The floor function returns the largest (closest to positive infinity)
6896 * number that is not greater than the argument and that is an integer.
6897 */
6898void
6899xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006900 double f;
6901
Owen Taylor3473f882001-02-23 17:55:21 +00006902 CHECK_ARITY(1);
6903 CAST_TO_NUMBER;
6904 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006905
6906 f = (double)((int) ctxt->value->floatval);
6907 if (f != ctxt->value->floatval) {
6908 if (ctxt->value->floatval > 0)
6909 ctxt->value->floatval = f;
6910 else
6911 ctxt->value->floatval = f - 1;
6912 }
Owen Taylor3473f882001-02-23 17:55:21 +00006913}
6914
6915/**
6916 * xmlXPathCeilingFunction:
6917 * @ctxt: the XPath Parser context
6918 * @nargs: the number of arguments
6919 *
6920 * Implement the ceiling() XPath function
6921 * number ceiling(number)
6922 * The ceiling function returns the smallest (closest to negative infinity)
6923 * number that is not less than the argument and that is an integer.
6924 */
6925void
6926xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6927 double f;
6928
6929 CHECK_ARITY(1);
6930 CAST_TO_NUMBER;
6931 CHECK_TYPE(XPATH_NUMBER);
6932
6933#if 0
6934 ctxt->value->floatval = ceil(ctxt->value->floatval);
6935#else
6936 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006937 if (f != ctxt->value->floatval) {
6938 if (ctxt->value->floatval > 0)
6939 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00006940 else {
6941 if (ctxt->value->floatval < 0 && f == 0)
6942 ctxt->value->floatval = xmlXPathNZERO;
6943 else
6944 ctxt->value->floatval = f;
6945 }
6946
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006947 }
Owen Taylor3473f882001-02-23 17:55:21 +00006948#endif
6949}
6950
6951/**
6952 * xmlXPathRoundFunction:
6953 * @ctxt: the XPath Parser context
6954 * @nargs: the number of arguments
6955 *
6956 * Implement the round() XPath function
6957 * number round(number)
6958 * The round function returns the number that is closest to the
6959 * argument and that is an integer. If there are two such numbers,
6960 * then the one that is even is returned.
6961 */
6962void
6963xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6964 double f;
6965
6966 CHECK_ARITY(1);
6967 CAST_TO_NUMBER;
6968 CHECK_TYPE(XPATH_NUMBER);
6969
Daniel Veillardcda96922001-08-21 10:56:31 +00006970 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
6971 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
6972 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00006973 (ctxt->value->floatval == 0.0))
6974 return;
6975
Owen Taylor3473f882001-02-23 17:55:21 +00006976 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006977 if (ctxt->value->floatval < 0) {
6978 if (ctxt->value->floatval < f - 0.5)
6979 ctxt->value->floatval = f - 1;
6980 else
6981 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00006982 if (ctxt->value->floatval == 0)
6983 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006984 } else {
6985 if (ctxt->value->floatval < f + 0.5)
6986 ctxt->value->floatval = f;
6987 else
6988 ctxt->value->floatval = f + 1;
6989 }
Owen Taylor3473f882001-02-23 17:55:21 +00006990}
6991
6992/************************************************************************
6993 * *
6994 * The Parser *
6995 * *
6996 ************************************************************************/
6997
6998/*
6999 * a couple of forward declarations since we use a recursive call based
7000 * implementation.
7001 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007002static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007003static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007004static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007005static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00007006static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
7007 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00007008
7009/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00007010 * xmlXPathCurrentChar:
7011 * @ctxt: the XPath parser context
7012 * @cur: pointer to the beginning of the char
7013 * @len: pointer to the length of the char read
7014 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007015 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00007016 * bytes in the input buffer.
7017 *
Daniel Veillard60087f32001-10-10 09:45:09 +00007018 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00007019 */
7020
7021static int
7022xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
7023 unsigned char c;
7024 unsigned int val;
7025 const xmlChar *cur;
7026
7027 if (ctxt == NULL)
7028 return(0);
7029 cur = ctxt->cur;
7030
7031 /*
7032 * We are supposed to handle UTF8, check it's valid
7033 * From rfc2044: encoding of the Unicode values on UTF-8:
7034 *
7035 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
7036 * 0000 0000-0000 007F 0xxxxxxx
7037 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
7038 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
7039 *
7040 * Check for the 0x110000 limit too
7041 */
7042 c = *cur;
7043 if (c & 0x80) {
7044 if ((cur[1] & 0xc0) != 0x80)
7045 goto encoding_error;
7046 if ((c & 0xe0) == 0xe0) {
7047
7048 if ((cur[2] & 0xc0) != 0x80)
7049 goto encoding_error;
7050 if ((c & 0xf0) == 0xf0) {
7051 if (((c & 0xf8) != 0xf0) ||
7052 ((cur[3] & 0xc0) != 0x80))
7053 goto encoding_error;
7054 /* 4-byte code */
7055 *len = 4;
7056 val = (cur[0] & 0x7) << 18;
7057 val |= (cur[1] & 0x3f) << 12;
7058 val |= (cur[2] & 0x3f) << 6;
7059 val |= cur[3] & 0x3f;
7060 } else {
7061 /* 3-byte code */
7062 *len = 3;
7063 val = (cur[0] & 0xf) << 12;
7064 val |= (cur[1] & 0x3f) << 6;
7065 val |= cur[2] & 0x3f;
7066 }
7067 } else {
7068 /* 2-byte code */
7069 *len = 2;
7070 val = (cur[0] & 0x1f) << 6;
7071 val |= cur[1] & 0x3f;
7072 }
7073 if (!IS_CHAR(val)) {
7074 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
7075 }
7076 return(val);
7077 } else {
7078 /* 1-byte code */
7079 *len = 1;
7080 return((int) *cur);
7081 }
7082encoding_error:
7083 /*
7084 * If we detect an UTF8 error that probably mean that the
7085 * input encoding didn't get properly advertized in the
7086 * declaration header. Report the error and switch the encoding
7087 * to ISO-Latin-1 (if you don't like this policy, just declare the
7088 * encoding !)
7089 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00007090 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00007091 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007092}
7093
7094/**
Owen Taylor3473f882001-02-23 17:55:21 +00007095 * xmlXPathParseNCName:
7096 * @ctxt: the XPath Parser context
7097 *
7098 * parse an XML namespace non qualified name.
7099 *
7100 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7101 *
7102 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7103 * CombiningChar | Extender
7104 *
7105 * Returns the namespace name or NULL
7106 */
7107
7108xmlChar *
7109xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00007110 const xmlChar *in;
7111 xmlChar *ret;
7112 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007113
Daniel Veillard2156a562001-04-28 12:24:34 +00007114 /*
7115 * Accelerator for simple ASCII names
7116 */
7117 in = ctxt->cur;
7118 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7119 ((*in >= 0x41) && (*in <= 0x5A)) ||
7120 (*in == '_')) {
7121 in++;
7122 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7123 ((*in >= 0x41) && (*in <= 0x5A)) ||
7124 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00007125 (*in == '_') || (*in == '.') ||
7126 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00007127 in++;
7128 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7129 (*in == '[') || (*in == ']') || (*in == ':') ||
7130 (*in == '@') || (*in == '*')) {
7131 count = in - ctxt->cur;
7132 if (count == 0)
7133 return(NULL);
7134 ret = xmlStrndup(ctxt->cur, count);
7135 ctxt->cur = in;
7136 return(ret);
7137 }
7138 }
7139 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00007140}
7141
Daniel Veillard2156a562001-04-28 12:24:34 +00007142
Owen Taylor3473f882001-02-23 17:55:21 +00007143/**
7144 * xmlXPathParseQName:
7145 * @ctxt: the XPath Parser context
7146 * @prefix: a xmlChar **
7147 *
7148 * parse an XML qualified name
7149 *
7150 * [NS 5] QName ::= (Prefix ':')? LocalPart
7151 *
7152 * [NS 6] Prefix ::= NCName
7153 *
7154 * [NS 7] LocalPart ::= NCName
7155 *
7156 * Returns the function returns the local part, and prefix is updated
7157 * to get the Prefix if any.
7158 */
7159
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007160static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007161xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7162 xmlChar *ret = NULL;
7163
7164 *prefix = NULL;
7165 ret = xmlXPathParseNCName(ctxt);
7166 if (CUR == ':') {
7167 *prefix = ret;
7168 NEXT;
7169 ret = xmlXPathParseNCName(ctxt);
7170 }
7171 return(ret);
7172}
7173
7174/**
7175 * xmlXPathParseName:
7176 * @ctxt: the XPath Parser context
7177 *
7178 * parse an XML name
7179 *
7180 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7181 * CombiningChar | Extender
7182 *
7183 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7184 *
7185 * Returns the namespace name or NULL
7186 */
7187
7188xmlChar *
7189xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007190 const xmlChar *in;
7191 xmlChar *ret;
7192 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007193
Daniel Veillard61d80a22001-04-27 17:13:01 +00007194 /*
7195 * Accelerator for simple ASCII names
7196 */
7197 in = ctxt->cur;
7198 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7199 ((*in >= 0x41) && (*in <= 0x5A)) ||
7200 (*in == '_') || (*in == ':')) {
7201 in++;
7202 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7203 ((*in >= 0x41) && (*in <= 0x5A)) ||
7204 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00007205 (*in == '_') || (*in == '-') ||
7206 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00007207 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007208 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007209 count = in - ctxt->cur;
7210 ret = xmlStrndup(ctxt->cur, count);
7211 ctxt->cur = in;
7212 return(ret);
7213 }
7214 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007215 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00007216}
7217
Daniel Veillard61d80a22001-04-27 17:13:01 +00007218static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00007219xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007220 xmlChar buf[XML_MAX_NAMELEN + 5];
7221 int len = 0, l;
7222 int c;
7223
7224 /*
7225 * Handler for more complex cases
7226 */
7227 c = CUR_CHAR(l);
7228 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00007229 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7230 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00007231 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00007232 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007233 return(NULL);
7234 }
7235
7236 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7237 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7238 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007239 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007240 (IS_COMBINING(c)) ||
7241 (IS_EXTENDER(c)))) {
7242 COPY_BUF(l,buf,len,c);
7243 NEXTL(l);
7244 c = CUR_CHAR(l);
7245 if (len >= XML_MAX_NAMELEN) {
7246 /*
7247 * Okay someone managed to make a huge name, so he's ready to pay
7248 * for the processing speed.
7249 */
7250 xmlChar *buffer;
7251 int max = len * 2;
7252
7253 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
7254 if (buffer == NULL) {
7255 XP_ERROR0(XPATH_MEMORY_ERROR);
7256 }
7257 memcpy(buffer, buf, len);
7258 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7259 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007260 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007261 (IS_COMBINING(c)) ||
7262 (IS_EXTENDER(c))) {
7263 if (len + 10 > max) {
7264 max *= 2;
7265 buffer = (xmlChar *) xmlRealloc(buffer,
7266 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007267 if (buffer == NULL) {
7268 XP_ERROR0(XPATH_MEMORY_ERROR);
7269 }
7270 }
7271 COPY_BUF(l,buffer,len,c);
7272 NEXTL(l);
7273 c = CUR_CHAR(l);
7274 }
7275 buffer[len] = 0;
7276 return(buffer);
7277 }
7278 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007279 if (len == 0)
7280 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007281 return(xmlStrndup(buf, len));
7282}
Daniel Veillard3cd72402002-05-13 10:33:30 +00007283
7284#define MAX_FRAC 20
7285
7286static double my_pow10[MAX_FRAC] = {
7287 1.0, 10.0, 100.0, 1000.0, 10000.0,
7288 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7289 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7290 100000000000000.0,
7291 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
7292 1000000000000000000.0, 10000000000000000000.0
7293};
7294
Owen Taylor3473f882001-02-23 17:55:21 +00007295/**
7296 * xmlXPathStringEvalNumber:
7297 * @str: A string to scan
7298 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00007299 * [30a] Float ::= Number ('e' Digits?)?
7300 *
Owen Taylor3473f882001-02-23 17:55:21 +00007301 * [30] Number ::= Digits ('.' Digits?)?
7302 * | '.' Digits
7303 * [31] Digits ::= [0-9]+
7304 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007305 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00007306 * In complement of the Number expression, this function also handles
7307 * negative values : '-' Number.
7308 *
7309 * Returns the double value.
7310 */
7311double
7312xmlXPathStringEvalNumber(const xmlChar *str) {
7313 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00007314 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007315 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007316 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007317 int exponent = 0;
7318 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007319#ifdef __GNUC__
7320 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007321 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007322#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00007323 if (cur == NULL) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00007324 while (IS_BLANK(*cur)) cur++;
7325 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7326 return(xmlXPathNAN);
7327 }
7328 if (*cur == '-') {
7329 isneg = 1;
7330 cur++;
7331 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007332
7333#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007334 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007335 * tmp/temp is a workaround against a gcc compiler bug
7336 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007337 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007338 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007339 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007340 ret = ret * 10;
7341 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00007342 ok = 1;
7343 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00007344 temp = (double) tmp;
7345 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007346 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007347#else
Daniel Veillard7b416132002-03-07 08:36:03 +00007348 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007349 while ((*cur >= '0') && (*cur <= '9')) {
7350 ret = ret * 10 + (*cur - '0');
7351 ok = 1;
7352 cur++;
7353 }
7354#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007355
Owen Taylor3473f882001-02-23 17:55:21 +00007356 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007357 int v, frac = 0;
7358 double fraction = 0;
7359
Owen Taylor3473f882001-02-23 17:55:21 +00007360 cur++;
7361 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7362 return(xmlXPathNAN);
7363 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007364 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
7365 v = (*cur - '0');
7366 fraction = fraction * 10 + v;
7367 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007368 cur++;
7369 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007370 fraction /= my_pow10[frac];
7371 ret = ret + fraction;
7372 while ((*cur >= '0') && (*cur <= '9'))
7373 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007374 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007375 if ((*cur == 'e') || (*cur == 'E')) {
7376 cur++;
7377 if (*cur == '-') {
7378 is_exponent_negative = 1;
7379 cur++;
7380 }
7381 while ((*cur >= '0') && (*cur <= '9')) {
7382 exponent = exponent * 10 + (*cur - '0');
7383 cur++;
7384 }
7385 }
Owen Taylor3473f882001-02-23 17:55:21 +00007386 while (IS_BLANK(*cur)) cur++;
7387 if (*cur != 0) return(xmlXPathNAN);
7388 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007389 if (is_exponent_negative) exponent = -exponent;
7390 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007391 return(ret);
7392}
7393
7394/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007395 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007396 * @ctxt: the XPath Parser context
7397 *
7398 * [30] Number ::= Digits ('.' Digits?)?
7399 * | '.' Digits
7400 * [31] Digits ::= [0-9]+
7401 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007402 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007403 *
7404 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007405static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007406xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7407{
Owen Taylor3473f882001-02-23 17:55:21 +00007408 double ret = 0.0;
7409 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007410 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007411 int exponent = 0;
7412 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007413#ifdef __GNUC__
7414 unsigned long tmp = 0;
7415 double temp;
7416#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007417
7418 CHECK_ERROR;
7419 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7420 XP_ERROR(XPATH_NUMBER_ERROR);
7421 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007422#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007423 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007424 * tmp/temp is a workaround against a gcc compiler bug
7425 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007426 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007427 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007428 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007429 ret = ret * 10;
7430 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007431 ok = 1;
7432 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007433 temp = (double) tmp;
7434 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007435 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007436#else
7437 ret = 0;
7438 while ((CUR >= '0') && (CUR <= '9')) {
7439 ret = ret * 10 + (CUR - '0');
7440 ok = 1;
7441 NEXT;
7442 }
7443#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007444 if (CUR == '.') {
7445 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007446 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7447 XP_ERROR(XPATH_NUMBER_ERROR);
7448 }
7449 while ((CUR >= '0') && (CUR <= '9')) {
7450 mult /= 10;
7451 ret = ret + (CUR - '0') * mult;
7452 NEXT;
7453 }
Owen Taylor3473f882001-02-23 17:55:21 +00007454 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007455 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007456 NEXT;
7457 if (CUR == '-') {
7458 is_exponent_negative = 1;
7459 NEXT;
7460 }
7461 while ((CUR >= '0') && (CUR <= '9')) {
7462 exponent = exponent * 10 + (CUR - '0');
7463 NEXT;
7464 }
7465 if (is_exponent_negative)
7466 exponent = -exponent;
7467 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007468 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007469 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007470 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007471}
7472
7473/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007474 * xmlXPathParseLiteral:
7475 * @ctxt: the XPath Parser context
7476 *
7477 * Parse a Literal
7478 *
7479 * [29] Literal ::= '"' [^"]* '"'
7480 * | "'" [^']* "'"
7481 *
7482 * Returns the value found or NULL in case of error
7483 */
7484static xmlChar *
7485xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7486 const xmlChar *q;
7487 xmlChar *ret = NULL;
7488
7489 if (CUR == '"') {
7490 NEXT;
7491 q = CUR_PTR;
7492 while ((IS_CHAR(CUR)) && (CUR != '"'))
7493 NEXT;
7494 if (!IS_CHAR(CUR)) {
7495 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7496 } else {
7497 ret = xmlStrndup(q, CUR_PTR - q);
7498 NEXT;
7499 }
7500 } else if (CUR == '\'') {
7501 NEXT;
7502 q = CUR_PTR;
7503 while ((IS_CHAR(CUR)) && (CUR != '\''))
7504 NEXT;
7505 if (!IS_CHAR(CUR)) {
7506 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7507 } else {
7508 ret = xmlStrndup(q, CUR_PTR - q);
7509 NEXT;
7510 }
7511 } else {
7512 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7513 }
7514 return(ret);
7515}
7516
7517/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007518 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007519 * @ctxt: the XPath Parser context
7520 *
7521 * Parse a Literal and push it on the stack.
7522 *
7523 * [29] Literal ::= '"' [^"]* '"'
7524 * | "'" [^']* "'"
7525 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007526 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007527 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007528static void
7529xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007530 const xmlChar *q;
7531 xmlChar *ret = NULL;
7532
7533 if (CUR == '"') {
7534 NEXT;
7535 q = CUR_PTR;
7536 while ((IS_CHAR(CUR)) && (CUR != '"'))
7537 NEXT;
7538 if (!IS_CHAR(CUR)) {
7539 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7540 } else {
7541 ret = xmlStrndup(q, CUR_PTR - q);
7542 NEXT;
7543 }
7544 } else if (CUR == '\'') {
7545 NEXT;
7546 q = CUR_PTR;
7547 while ((IS_CHAR(CUR)) && (CUR != '\''))
7548 NEXT;
7549 if (!IS_CHAR(CUR)) {
7550 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7551 } else {
7552 ret = xmlStrndup(q, CUR_PTR - q);
7553 NEXT;
7554 }
7555 } else {
7556 XP_ERROR(XPATH_START_LITERAL_ERROR);
7557 }
7558 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007559 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7560 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007561 xmlFree(ret);
7562}
7563
7564/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007565 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007566 * @ctxt: the XPath Parser context
7567 *
7568 * Parse a VariableReference, evaluate it and push it on the stack.
7569 *
7570 * The variable bindings consist of a mapping from variable names
7571 * to variable values. The value of a variable is an object, which
7572 * of any of the types that are possible for the value of an expression,
7573 * and may also be of additional types not specified here.
7574 *
7575 * Early evaluation is possible since:
7576 * The variable bindings [...] used to evaluate a subexpression are
7577 * always the same as those used to evaluate the containing expression.
7578 *
7579 * [36] VariableReference ::= '$' QName
7580 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007581static void
7582xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007583 xmlChar *name;
7584 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007585
7586 SKIP_BLANKS;
7587 if (CUR != '$') {
7588 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7589 }
7590 NEXT;
7591 name = xmlXPathParseQName(ctxt, &prefix);
7592 if (name == NULL) {
7593 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7594 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007595 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007596 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7597 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007598 SKIP_BLANKS;
7599}
7600
7601/**
7602 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +00007603 * @name: a name string
7604 *
7605 * Is the name given a NodeType one.
7606 *
7607 * [38] NodeType ::= 'comment'
7608 * | 'text'
7609 * | 'processing-instruction'
7610 * | 'node'
7611 *
7612 * Returns 1 if true 0 otherwise
7613 */
7614int
7615xmlXPathIsNodeType(const xmlChar *name) {
7616 if (name == NULL)
7617 return(0);
7618
Daniel Veillard1971ee22002-01-31 20:29:19 +00007619 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007620 return(1);
7621 if (xmlStrEqual(name, BAD_CAST "text"))
7622 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007623 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007624 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007625 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007626 return(1);
7627 return(0);
7628}
7629
7630/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007631 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007632 * @ctxt: the XPath Parser context
7633 *
7634 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7635 * [17] Argument ::= Expr
7636 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007637 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007638 * pushed on the stack
7639 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007640static void
7641xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007642 xmlChar *name;
7643 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007644 int nbargs = 0;
7645
7646 name = xmlXPathParseQName(ctxt, &prefix);
7647 if (name == NULL) {
7648 XP_ERROR(XPATH_EXPR_ERROR);
7649 }
7650 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007651#ifdef DEBUG_EXPR
7652 if (prefix == NULL)
7653 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7654 name);
7655 else
7656 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7657 prefix, name);
7658#endif
7659
Owen Taylor3473f882001-02-23 17:55:21 +00007660 if (CUR != '(') {
7661 XP_ERROR(XPATH_EXPR_ERROR);
7662 }
7663 NEXT;
7664 SKIP_BLANKS;
7665
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007666 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +00007667 if (CUR != ')') {
7668 while (CUR != 0) {
7669 int op1 = ctxt->comp->last;
7670 ctxt->comp->last = -1;
7671 xmlXPathCompileExpr(ctxt);
7672 CHECK_ERROR;
7673 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
7674 nbargs++;
7675 if (CUR == ')') break;
7676 if (CUR != ',') {
7677 XP_ERROR(XPATH_EXPR_ERROR);
7678 }
7679 NEXT;
7680 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007681 }
Owen Taylor3473f882001-02-23 17:55:21 +00007682 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007683 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7684 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007685 NEXT;
7686 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007687}
7688
7689/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007690 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007691 * @ctxt: the XPath Parser context
7692 *
7693 * [15] PrimaryExpr ::= VariableReference
7694 * | '(' Expr ')'
7695 * | Literal
7696 * | Number
7697 * | FunctionCall
7698 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007699 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007700 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007701static void
7702xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007703 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007704 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007705 else if (CUR == '(') {
7706 NEXT;
7707 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007708 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007709 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00007710 if (CUR != ')') {
7711 XP_ERROR(XPATH_EXPR_ERROR);
7712 }
7713 NEXT;
7714 SKIP_BLANKS;
Daniel Veillard01917aa2002-04-10 11:30:41 +00007715 } else if (IS_DIGIT(CUR) || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007716 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007717 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007718 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007719 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007720 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007721 }
7722 SKIP_BLANKS;
7723}
7724
7725/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007726 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007727 * @ctxt: the XPath Parser context
7728 *
7729 * [20] FilterExpr ::= PrimaryExpr
7730 * | FilterExpr Predicate
7731 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007732 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007733 * Square brackets are used to filter expressions in the same way that
7734 * they are used in location paths. It is an error if the expression to
7735 * be filtered does not evaluate to a node-set. The context node list
7736 * used for evaluating the expression in square brackets is the node-set
7737 * to be filtered listed in document order.
7738 */
7739
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007740static void
7741xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
7742 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007743 CHECK_ERROR;
7744 SKIP_BLANKS;
7745
7746 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007747 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00007748 SKIP_BLANKS;
7749 }
7750
7751
7752}
7753
7754/**
7755 * xmlXPathScanName:
7756 * @ctxt: the XPath Parser context
7757 *
7758 * Trickery: parse an XML name but without consuming the input flow
7759 * Needed to avoid insanity in the parser state.
7760 *
7761 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7762 * CombiningChar | Extender
7763 *
7764 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7765 *
7766 * [6] Names ::= Name (S Name)*
7767 *
7768 * Returns the Name parsed or NULL
7769 */
7770
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007771static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007772xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7773 xmlChar buf[XML_MAX_NAMELEN];
7774 int len = 0;
7775
7776 SKIP_BLANKS;
7777 if (!IS_LETTER(CUR) && (CUR != '_') &&
7778 (CUR != ':')) {
7779 return(NULL);
7780 }
7781
7782 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7783 (NXT(len) == '.') || (NXT(len) == '-') ||
7784 (NXT(len) == '_') || (NXT(len) == ':') ||
7785 (IS_COMBINING(NXT(len))) ||
7786 (IS_EXTENDER(NXT(len)))) {
7787 buf[len] = NXT(len);
7788 len++;
7789 if (len >= XML_MAX_NAMELEN) {
7790 xmlGenericError(xmlGenericErrorContext,
7791 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
7792 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7793 (NXT(len) == '.') || (NXT(len) == '-') ||
7794 (NXT(len) == '_') || (NXT(len) == ':') ||
7795 (IS_COMBINING(NXT(len))) ||
7796 (IS_EXTENDER(NXT(len))))
7797 len++;
7798 break;
7799 }
7800 }
7801 return(xmlStrndup(buf, len));
7802}
7803
7804/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007805 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007806 * @ctxt: the XPath Parser context
7807 *
7808 * [19] PathExpr ::= LocationPath
7809 * | FilterExpr
7810 * | FilterExpr '/' RelativeLocationPath
7811 * | FilterExpr '//' RelativeLocationPath
7812 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007813 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007814 * The / operator and // operators combine an arbitrary expression
7815 * and a relative location path. It is an error if the expression
7816 * does not evaluate to a node-set.
7817 * The / operator does composition in the same way as when / is
7818 * used in a location path. As in location paths, // is short for
7819 * /descendant-or-self::node()/.
7820 */
7821
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007822static void
7823xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007824 int lc = 1; /* Should we branch to LocationPath ? */
7825 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7826
7827 SKIP_BLANKS;
7828 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
Daniel Veillard01917aa2002-04-10 11:30:41 +00007829 (CUR == '\'') || (CUR == '"') || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00007830 lc = 0;
7831 } else if (CUR == '*') {
7832 /* relative or absolute location path */
7833 lc = 1;
7834 } else if (CUR == '/') {
7835 /* relative or absolute location path */
7836 lc = 1;
7837 } else if (CUR == '@') {
7838 /* relative abbreviated attribute location path */
7839 lc = 1;
7840 } else if (CUR == '.') {
7841 /* relative abbreviated attribute location path */
7842 lc = 1;
7843 } else {
7844 /*
7845 * Problem is finding if we have a name here whether it's:
7846 * - a nodetype
7847 * - a function call in which case it's followed by '('
7848 * - an axis in which case it's followed by ':'
7849 * - a element name
7850 * We do an a priori analysis here rather than having to
7851 * maintain parsed token content through the recursive function
7852 * calls. This looks uglier but makes the code quite easier to
7853 * read/write/debug.
7854 */
7855 SKIP_BLANKS;
7856 name = xmlXPathScanName(ctxt);
7857 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7858#ifdef DEBUG_STEP
7859 xmlGenericError(xmlGenericErrorContext,
7860 "PathExpr: Axis\n");
7861#endif
7862 lc = 1;
7863 xmlFree(name);
7864 } else if (name != NULL) {
7865 int len =xmlStrlen(name);
7866 int blank = 0;
7867
7868
7869 while (NXT(len) != 0) {
7870 if (NXT(len) == '/') {
7871 /* element name */
7872#ifdef DEBUG_STEP
7873 xmlGenericError(xmlGenericErrorContext,
7874 "PathExpr: AbbrRelLocation\n");
7875#endif
7876 lc = 1;
7877 break;
7878 } else if (IS_BLANK(NXT(len))) {
7879 /* skip to next */
7880 blank = 1;
7881 } else if (NXT(len) == ':') {
7882#ifdef DEBUG_STEP
7883 xmlGenericError(xmlGenericErrorContext,
7884 "PathExpr: AbbrRelLocation\n");
7885#endif
7886 lc = 1;
7887 break;
7888 } else if ((NXT(len) == '(')) {
7889 /* Note Type or Function */
7890 if (xmlXPathIsNodeType(name)) {
7891#ifdef DEBUG_STEP
7892 xmlGenericError(xmlGenericErrorContext,
7893 "PathExpr: Type search\n");
7894#endif
7895 lc = 1;
7896 } else {
7897#ifdef DEBUG_STEP
7898 xmlGenericError(xmlGenericErrorContext,
7899 "PathExpr: function call\n");
7900#endif
7901 lc = 0;
7902 }
7903 break;
7904 } else if ((NXT(len) == '[')) {
7905 /* element name */
7906#ifdef DEBUG_STEP
7907 xmlGenericError(xmlGenericErrorContext,
7908 "PathExpr: AbbrRelLocation\n");
7909#endif
7910 lc = 1;
7911 break;
7912 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
7913 (NXT(len) == '=')) {
7914 lc = 1;
7915 break;
7916 } else {
7917 lc = 1;
7918 break;
7919 }
7920 len++;
7921 }
7922 if (NXT(len) == 0) {
7923#ifdef DEBUG_STEP
7924 xmlGenericError(xmlGenericErrorContext,
7925 "PathExpr: AbbrRelLocation\n");
7926#endif
7927 /* element name */
7928 lc = 1;
7929 }
7930 xmlFree(name);
7931 } else {
7932 /* make sure all cases are covered explicitely */
7933 XP_ERROR(XPATH_EXPR_ERROR);
7934 }
7935 }
7936
7937 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007938 if (CUR == '/') {
7939 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
7940 } else {
7941 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007942 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007943 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007944 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007945 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007946 CHECK_ERROR;
7947 if ((CUR == '/') && (NXT(1) == '/')) {
7948 SKIP(2);
7949 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007950
7951 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7952 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
7953 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
7954
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007955 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007956 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007957 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007958 }
7959 }
7960 SKIP_BLANKS;
7961}
7962
7963/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007964 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007965 * @ctxt: the XPath Parser context
7966 *
7967 * [18] UnionExpr ::= PathExpr
7968 * | UnionExpr '|' PathExpr
7969 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007970 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007971 */
7972
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007973static void
7974xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
7975 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007976 CHECK_ERROR;
7977 SKIP_BLANKS;
7978 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007979 int op1 = ctxt->comp->last;
7980 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007981
7982 NEXT;
7983 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007984 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007985
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007986 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
7987
Owen Taylor3473f882001-02-23 17:55:21 +00007988 SKIP_BLANKS;
7989 }
Owen Taylor3473f882001-02-23 17:55:21 +00007990}
7991
7992/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007993 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007994 * @ctxt: the XPath Parser context
7995 *
7996 * [27] UnaryExpr ::= UnionExpr
7997 * | '-' UnaryExpr
7998 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007999 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008000 */
8001
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008002static void
8003xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008004 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008005 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008006
8007 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00008008 while (CUR == '-') {
8009 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008010 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008011 NEXT;
8012 SKIP_BLANKS;
8013 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008014
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008015 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008016 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008017 if (found) {
8018 if (minus)
8019 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8020 else
8021 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008022 }
8023}
8024
8025/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008026 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008027 * @ctxt: the XPath Parser context
8028 *
8029 * [26] MultiplicativeExpr ::= UnaryExpr
8030 * | MultiplicativeExpr MultiplyOperator UnaryExpr
8031 * | MultiplicativeExpr 'div' UnaryExpr
8032 * | MultiplicativeExpr 'mod' UnaryExpr
8033 * [34] MultiplyOperator ::= '*'
8034 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008035 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008036 */
8037
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008038static void
8039xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8040 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008041 CHECK_ERROR;
8042 SKIP_BLANKS;
8043 while ((CUR == '*') ||
8044 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8045 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8046 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008047 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008048
8049 if (CUR == '*') {
8050 op = 0;
8051 NEXT;
8052 } else if (CUR == 'd') {
8053 op = 1;
8054 SKIP(3);
8055 } else if (CUR == 'm') {
8056 op = 2;
8057 SKIP(3);
8058 }
8059 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008060 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008061 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008062 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008063 SKIP_BLANKS;
8064 }
8065}
8066
8067/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008068 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008069 * @ctxt: the XPath Parser context
8070 *
8071 * [25] AdditiveExpr ::= MultiplicativeExpr
8072 * | AdditiveExpr '+' MultiplicativeExpr
8073 * | AdditiveExpr '-' MultiplicativeExpr
8074 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008075 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008076 */
8077
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008078static void
8079xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008080
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008081 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008082 CHECK_ERROR;
8083 SKIP_BLANKS;
8084 while ((CUR == '+') || (CUR == '-')) {
8085 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008086 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008087
8088 if (CUR == '+') plus = 1;
8089 else plus = 0;
8090 NEXT;
8091 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008092 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008093 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008094 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008095 SKIP_BLANKS;
8096 }
8097}
8098
8099/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008100 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008101 * @ctxt: the XPath Parser context
8102 *
8103 * [24] RelationalExpr ::= AdditiveExpr
8104 * | RelationalExpr '<' AdditiveExpr
8105 * | RelationalExpr '>' AdditiveExpr
8106 * | RelationalExpr '<=' AdditiveExpr
8107 * | RelationalExpr '>=' AdditiveExpr
8108 *
8109 * A <= B > C is allowed ? Answer from James, yes with
8110 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8111 * which is basically what got implemented.
8112 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008113 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00008114 * on the stack
8115 */
8116
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008117static void
8118xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8119 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008120 CHECK_ERROR;
8121 SKIP_BLANKS;
8122 while ((CUR == '<') ||
8123 (CUR == '>') ||
8124 ((CUR == '<') && (NXT(1) == '=')) ||
8125 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008126 int inf, strict;
8127 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008128
8129 if (CUR == '<') inf = 1;
8130 else inf = 0;
8131 if (NXT(1) == '=') strict = 0;
8132 else strict = 1;
8133 NEXT;
8134 if (!strict) NEXT;
8135 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008136 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008137 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008138 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00008139 SKIP_BLANKS;
8140 }
8141}
8142
8143/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008144 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008145 * @ctxt: the XPath Parser context
8146 *
8147 * [23] EqualityExpr ::= RelationalExpr
8148 * | EqualityExpr '=' RelationalExpr
8149 * | EqualityExpr '!=' RelationalExpr
8150 *
8151 * A != B != C is allowed ? Answer from James, yes with
8152 * (RelationalExpr = RelationalExpr) = RelationalExpr
8153 * (RelationalExpr != RelationalExpr) != RelationalExpr
8154 * which is basically what got implemented.
8155 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008156 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008157 *
8158 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008159static void
8160xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8161 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008162 CHECK_ERROR;
8163 SKIP_BLANKS;
8164 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008165 int eq;
8166 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008167
8168 if (CUR == '=') eq = 1;
8169 else eq = 0;
8170 NEXT;
8171 if (!eq) NEXT;
8172 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008173 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008174 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008175 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008176 SKIP_BLANKS;
8177 }
8178}
8179
8180/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008181 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008182 * @ctxt: the XPath Parser context
8183 *
8184 * [22] AndExpr ::= EqualityExpr
8185 * | AndExpr 'and' EqualityExpr
8186 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008187 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008188 *
8189 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008190static void
8191xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8192 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008193 CHECK_ERROR;
8194 SKIP_BLANKS;
8195 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008196 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008197 SKIP(3);
8198 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008199 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008200 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008201 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008202 SKIP_BLANKS;
8203 }
8204}
8205
8206/**
Daniel Veillard591b4be2003-02-09 23:33:36 +00008207 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008208 * @ctxt: the XPath Parser context
8209 *
8210 * [14] Expr ::= OrExpr
8211 * [21] OrExpr ::= AndExpr
8212 * | OrExpr 'or' AndExpr
8213 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008214 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00008215 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008216static void
8217xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8218 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008219 CHECK_ERROR;
8220 SKIP_BLANKS;
8221 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008222 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008223 SKIP(2);
8224 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008225 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008226 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008227 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8228 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00008229 SKIP_BLANKS;
8230 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008231 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8232 /* more ops could be optimized too */
8233 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8234 }
Owen Taylor3473f882001-02-23 17:55:21 +00008235}
8236
8237/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008238 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00008239 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008240 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00008241 *
8242 * [8] Predicate ::= '[' PredicateExpr ']'
8243 * [9] PredicateExpr ::= Expr
8244 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008245 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008246 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008247static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008248xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008249 int op1 = ctxt->comp->last;
8250
8251 SKIP_BLANKS;
8252 if (CUR != '[') {
8253 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8254 }
8255 NEXT;
8256 SKIP_BLANKS;
8257
8258 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008259 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008260 CHECK_ERROR;
8261
8262 if (CUR != ']') {
8263 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8264 }
8265
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008266 if (filter)
8267 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8268 else
8269 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008270
8271 NEXT;
8272 SKIP_BLANKS;
8273}
8274
8275/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008276 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00008277 * @ctxt: the XPath Parser context
8278 * @test: pointer to a xmlXPathTestVal
8279 * @type: pointer to a xmlXPathTypeVal
8280 * @prefix: placeholder for a possible name prefix
8281 *
8282 * [7] NodeTest ::= NameTest
8283 * | NodeType '(' ')'
8284 * | 'processing-instruction' '(' Literal ')'
8285 *
8286 * [37] NameTest ::= '*'
8287 * | NCName ':' '*'
8288 * | QName
8289 * [38] NodeType ::= 'comment'
8290 * | 'text'
8291 * | 'processing-instruction'
8292 * | 'node'
8293 *
8294 * Returns the name found and update @test, @type and @prefix appropriately
8295 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008296static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008297xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8298 xmlXPathTypeVal *type, const xmlChar **prefix,
8299 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008300 int blanks;
8301
8302 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8303 STRANGE;
8304 return(NULL);
8305 }
8306 *type = 0;
8307 *test = 0;
8308 *prefix = NULL;
8309 SKIP_BLANKS;
8310
8311 if ((name == NULL) && (CUR == '*')) {
8312 /*
8313 * All elements
8314 */
8315 NEXT;
8316 *test = NODE_TEST_ALL;
8317 return(NULL);
8318 }
8319
8320 if (name == NULL)
8321 name = xmlXPathParseNCName(ctxt);
8322 if (name == NULL) {
8323 XP_ERROR0(XPATH_EXPR_ERROR);
8324 }
8325
8326 blanks = IS_BLANK(CUR);
8327 SKIP_BLANKS;
8328 if (CUR == '(') {
8329 NEXT;
8330 /*
8331 * NodeType or PI search
8332 */
8333 if (xmlStrEqual(name, BAD_CAST "comment"))
8334 *type = NODE_TYPE_COMMENT;
8335 else if (xmlStrEqual(name, BAD_CAST "node"))
8336 *type = NODE_TYPE_NODE;
8337 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8338 *type = NODE_TYPE_PI;
8339 else if (xmlStrEqual(name, BAD_CAST "text"))
8340 *type = NODE_TYPE_TEXT;
8341 else {
8342 if (name != NULL)
8343 xmlFree(name);
8344 XP_ERROR0(XPATH_EXPR_ERROR);
8345 }
8346
8347 *test = NODE_TEST_TYPE;
8348
8349 SKIP_BLANKS;
8350 if (*type == NODE_TYPE_PI) {
8351 /*
8352 * Specific case: search a PI by name.
8353 */
Owen Taylor3473f882001-02-23 17:55:21 +00008354 if (name != NULL)
8355 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008356 name = NULL;
8357 if (CUR != ')') {
8358 name = xmlXPathParseLiteral(ctxt);
8359 CHECK_ERROR 0;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00008360 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00008361 SKIP_BLANKS;
8362 }
Owen Taylor3473f882001-02-23 17:55:21 +00008363 }
8364 if (CUR != ')') {
8365 if (name != NULL)
8366 xmlFree(name);
8367 XP_ERROR0(XPATH_UNCLOSED_ERROR);
8368 }
8369 NEXT;
8370 return(name);
8371 }
8372 *test = NODE_TEST_NAME;
8373 if ((!blanks) && (CUR == ':')) {
8374 NEXT;
8375
8376 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008377 * Since currently the parser context don't have a
8378 * namespace list associated:
8379 * The namespace name for this prefix can be computed
8380 * only at evaluation time. The compilation is done
8381 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008382 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008383#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008384 *prefix = xmlXPathNsLookup(ctxt->context, name);
8385 if (name != NULL)
8386 xmlFree(name);
8387 if (*prefix == NULL) {
8388 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8389 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008390#else
8391 *prefix = name;
8392#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008393
8394 if (CUR == '*') {
8395 /*
8396 * All elements
8397 */
8398 NEXT;
8399 *test = NODE_TEST_ALL;
8400 return(NULL);
8401 }
8402
8403 name = xmlXPathParseNCName(ctxt);
8404 if (name == NULL) {
8405 XP_ERROR0(XPATH_EXPR_ERROR);
8406 }
8407 }
8408 return(name);
8409}
8410
8411/**
8412 * xmlXPathIsAxisName:
8413 * @name: a preparsed name token
8414 *
8415 * [6] AxisName ::= 'ancestor'
8416 * | 'ancestor-or-self'
8417 * | 'attribute'
8418 * | 'child'
8419 * | 'descendant'
8420 * | 'descendant-or-self'
8421 * | 'following'
8422 * | 'following-sibling'
8423 * | 'namespace'
8424 * | 'parent'
8425 * | 'preceding'
8426 * | 'preceding-sibling'
8427 * | 'self'
8428 *
8429 * Returns the axis or 0
8430 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008431static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008432xmlXPathIsAxisName(const xmlChar *name) {
8433 xmlXPathAxisVal ret = 0;
8434 switch (name[0]) {
8435 case 'a':
8436 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8437 ret = AXIS_ANCESTOR;
8438 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8439 ret = AXIS_ANCESTOR_OR_SELF;
8440 if (xmlStrEqual(name, BAD_CAST "attribute"))
8441 ret = AXIS_ATTRIBUTE;
8442 break;
8443 case 'c':
8444 if (xmlStrEqual(name, BAD_CAST "child"))
8445 ret = AXIS_CHILD;
8446 break;
8447 case 'd':
8448 if (xmlStrEqual(name, BAD_CAST "descendant"))
8449 ret = AXIS_DESCENDANT;
8450 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8451 ret = AXIS_DESCENDANT_OR_SELF;
8452 break;
8453 case 'f':
8454 if (xmlStrEqual(name, BAD_CAST "following"))
8455 ret = AXIS_FOLLOWING;
8456 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8457 ret = AXIS_FOLLOWING_SIBLING;
8458 break;
8459 case 'n':
8460 if (xmlStrEqual(name, BAD_CAST "namespace"))
8461 ret = AXIS_NAMESPACE;
8462 break;
8463 case 'p':
8464 if (xmlStrEqual(name, BAD_CAST "parent"))
8465 ret = AXIS_PARENT;
8466 if (xmlStrEqual(name, BAD_CAST "preceding"))
8467 ret = AXIS_PRECEDING;
8468 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8469 ret = AXIS_PRECEDING_SIBLING;
8470 break;
8471 case 's':
8472 if (xmlStrEqual(name, BAD_CAST "self"))
8473 ret = AXIS_SELF;
8474 break;
8475 }
8476 return(ret);
8477}
8478
8479/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008480 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008481 * @ctxt: the XPath Parser context
8482 *
8483 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8484 * | AbbreviatedStep
8485 *
8486 * [12] AbbreviatedStep ::= '.' | '..'
8487 *
8488 * [5] AxisSpecifier ::= AxisName '::'
8489 * | AbbreviatedAxisSpecifier
8490 *
8491 * [13] AbbreviatedAxisSpecifier ::= '@'?
8492 *
8493 * Modified for XPtr range support as:
8494 *
8495 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8496 * | AbbreviatedStep
8497 * | 'range-to' '(' Expr ')' Predicate*
8498 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008499 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008500 * A location step of . is short for self::node(). This is
8501 * particularly useful in conjunction with //. For example, the
8502 * location path .//para is short for
8503 * self::node()/descendant-or-self::node()/child::para
8504 * and so will select all para descendant elements of the context
8505 * node.
8506 * Similarly, a location step of .. is short for parent::node().
8507 * For example, ../title is short for parent::node()/child::title
8508 * and so will select the title children of the parent of the context
8509 * node.
8510 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008511static void
8512xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008513#ifdef LIBXML_XPTR_ENABLED
8514 int rangeto = 0;
8515 int op2 = -1;
8516#endif
8517
Owen Taylor3473f882001-02-23 17:55:21 +00008518 SKIP_BLANKS;
8519 if ((CUR == '.') && (NXT(1) == '.')) {
8520 SKIP(2);
8521 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008522 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8523 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008524 } else if (CUR == '.') {
8525 NEXT;
8526 SKIP_BLANKS;
8527 } else {
8528 xmlChar *name = NULL;
8529 const xmlChar *prefix = NULL;
8530 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008531 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008532 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008533 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008534
8535 /*
8536 * The modification needed for XPointer change to the production
8537 */
8538#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008539 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008540 name = xmlXPathParseNCName(ctxt);
8541 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008542 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008543 xmlFree(name);
8544 SKIP_BLANKS;
8545 if (CUR != '(') {
8546 XP_ERROR(XPATH_EXPR_ERROR);
8547 }
8548 NEXT;
8549 SKIP_BLANKS;
8550
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008551 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008552 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008553 CHECK_ERROR;
8554
8555 SKIP_BLANKS;
8556 if (CUR != ')') {
8557 XP_ERROR(XPATH_EXPR_ERROR);
8558 }
8559 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008560 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008561 goto eval_predicates;
8562 }
8563 }
8564#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008565 if (CUR == '*') {
8566 axis = AXIS_CHILD;
8567 } else {
8568 if (name == NULL)
8569 name = xmlXPathParseNCName(ctxt);
8570 if (name != NULL) {
8571 axis = xmlXPathIsAxisName(name);
8572 if (axis != 0) {
8573 SKIP_BLANKS;
8574 if ((CUR == ':') && (NXT(1) == ':')) {
8575 SKIP(2);
8576 xmlFree(name);
8577 name = NULL;
8578 } else {
8579 /* an element name can conflict with an axis one :-\ */
8580 axis = AXIS_CHILD;
8581 }
Owen Taylor3473f882001-02-23 17:55:21 +00008582 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008583 axis = AXIS_CHILD;
8584 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008585 } else if (CUR == '@') {
8586 NEXT;
8587 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008588 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008589 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008590 }
Owen Taylor3473f882001-02-23 17:55:21 +00008591 }
8592
8593 CHECK_ERROR;
8594
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008595 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008596 if (test == 0)
8597 return;
8598
8599#ifdef DEBUG_STEP
8600 xmlGenericError(xmlGenericErrorContext,
8601 "Basis : computing new set\n");
8602#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008603
Owen Taylor3473f882001-02-23 17:55:21 +00008604#ifdef DEBUG_STEP
8605 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008606 if (ctxt->value == NULL)
8607 xmlGenericError(xmlGenericErrorContext, "no value\n");
8608 else if (ctxt->value->nodesetval == NULL)
8609 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8610 else
8611 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008612#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008613
8614eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008615 op1 = ctxt->comp->last;
8616 ctxt->comp->last = -1;
8617
Owen Taylor3473f882001-02-23 17:55:21 +00008618 SKIP_BLANKS;
8619 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008620 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008621 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008622
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008623#ifdef LIBXML_XPTR_ENABLED
8624 if (rangeto) {
8625 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8626 } else
8627#endif
8628 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8629 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008630
Owen Taylor3473f882001-02-23 17:55:21 +00008631 }
8632#ifdef DEBUG_STEP
8633 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008634 if (ctxt->value == NULL)
8635 xmlGenericError(xmlGenericErrorContext, "no value\n");
8636 else if (ctxt->value->nodesetval == NULL)
8637 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8638 else
8639 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8640 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008641#endif
8642}
8643
8644/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008645 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008646 * @ctxt: the XPath Parser context
8647 *
8648 * [3] RelativeLocationPath ::= Step
8649 * | RelativeLocationPath '/' Step
8650 * | AbbreviatedRelativeLocationPath
8651 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8652 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008653 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008654 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008655static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008656xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008657(xmlXPathParserContextPtr ctxt) {
8658 SKIP_BLANKS;
8659 if ((CUR == '/') && (NXT(1) == '/')) {
8660 SKIP(2);
8661 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008662 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8663 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008664 } else if (CUR == '/') {
8665 NEXT;
8666 SKIP_BLANKS;
8667 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008668 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008669 SKIP_BLANKS;
8670 while (CUR == '/') {
8671 if ((CUR == '/') && (NXT(1) == '/')) {
8672 SKIP(2);
8673 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008674 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008675 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008676 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008677 } else if (CUR == '/') {
8678 NEXT;
8679 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008680 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008681 }
8682 SKIP_BLANKS;
8683 }
8684}
8685
8686/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008687 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008688 * @ctxt: the XPath Parser context
8689 *
8690 * [1] LocationPath ::= RelativeLocationPath
8691 * | AbsoluteLocationPath
8692 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8693 * | AbbreviatedAbsoluteLocationPath
8694 * [10] AbbreviatedAbsoluteLocationPath ::=
8695 * '//' RelativeLocationPath
8696 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008697 * Compile a location path
8698 *
Owen Taylor3473f882001-02-23 17:55:21 +00008699 * // is short for /descendant-or-self::node()/. For example,
8700 * //para is short for /descendant-or-self::node()/child::para and
8701 * so will select any para element in the document (even a para element
8702 * that is a document element will be selected by //para since the
8703 * document element node is a child of the root node); div//para is
8704 * short for div/descendant-or-self::node()/child::para and so will
8705 * select all para descendants of div children.
8706 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008707static void
8708xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008709 SKIP_BLANKS;
8710 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008711 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008712 } else {
8713 while (CUR == '/') {
8714 if ((CUR == '/') && (NXT(1) == '/')) {
8715 SKIP(2);
8716 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008717 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8718 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008719 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008720 } else if (CUR == '/') {
8721 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008722 SKIP_BLANKS;
8723 if ((CUR != 0 ) &&
8724 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
8725 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008726 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008727 }
8728 }
8729 }
8730}
8731
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008732/************************************************************************
8733 * *
8734 * XPath precompiled expression evaluation *
8735 * *
8736 ************************************************************************/
8737
Daniel Veillardf06307e2001-07-03 10:35:50 +00008738static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008739xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8740
8741/**
8742 * xmlXPathNodeCollectAndTest:
8743 * @ctxt: the XPath Parser context
8744 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008745 * @first: pointer to the first element in document order
8746 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008747 *
8748 * This is the function implementing a step: based on the current list
8749 * of nodes, it builds up a new list, looking at all nodes under that
8750 * axis and selecting them it also do the predicate filtering
8751 *
8752 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00008753 *
8754 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008755 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008756static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008757xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008758 xmlXPathStepOpPtr op,
8759 xmlNodePtr * first, xmlNodePtr * last)
8760{
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008761 xmlXPathAxisVal axis = op->value;
8762 xmlXPathTestVal test = op->value2;
8763 xmlXPathTypeVal type = op->value3;
8764 const xmlChar *prefix = op->value4;
8765 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008766 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008767
8768#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008769 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008770#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008771 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008772 xmlNodeSetPtr ret, list;
8773 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008774 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00008775 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008776 xmlNodePtr cur = NULL;
8777 xmlXPathObjectPtr obj;
8778 xmlNodeSetPtr nodelist;
8779 xmlNodePtr tmp;
8780
Daniel Veillardf06307e2001-07-03 10:35:50 +00008781 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008782 obj = valuePop(ctxt);
8783 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00008784 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008785 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008786 URI = xmlXPathNsLookup(ctxt->context, prefix);
8787 if (URI == NULL)
8788 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008789 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008790#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008791 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008792#endif
8793 switch (axis) {
8794 case AXIS_ANCESTOR:
8795#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008796 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008797#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008798 first = NULL;
8799 next = xmlXPathNextAncestor;
8800 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008801 case AXIS_ANCESTOR_OR_SELF:
8802#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008803 xmlGenericError(xmlGenericErrorContext,
8804 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008805#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008806 first = NULL;
8807 next = xmlXPathNextAncestorOrSelf;
8808 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008809 case AXIS_ATTRIBUTE:
8810#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008811 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008812#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008813 first = NULL;
8814 last = NULL;
8815 next = xmlXPathNextAttribute;
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_CHILD:
8819#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008820 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008821#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008822 last = NULL;
8823 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00008824 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008825 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008826 case AXIS_DESCENDANT:
8827#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008828 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008829#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008830 last = NULL;
8831 next = xmlXPathNextDescendant;
8832 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008833 case AXIS_DESCENDANT_OR_SELF:
8834#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008835 xmlGenericError(xmlGenericErrorContext,
8836 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008837#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008838 last = NULL;
8839 next = xmlXPathNextDescendantOrSelf;
8840 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008841 case AXIS_FOLLOWING:
8842#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008843 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008844#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008845 last = NULL;
8846 next = xmlXPathNextFollowing;
8847 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008848 case AXIS_FOLLOWING_SIBLING:
8849#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008850 xmlGenericError(xmlGenericErrorContext,
8851 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008852#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008853 last = NULL;
8854 next = xmlXPathNextFollowingSibling;
8855 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008856 case AXIS_NAMESPACE:
8857#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008858 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008859#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008860 first = NULL;
8861 last = NULL;
8862 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00008863 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008864 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008865 case AXIS_PARENT:
8866#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008867 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008868#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008869 first = NULL;
8870 next = xmlXPathNextParent;
8871 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008872 case AXIS_PRECEDING:
8873#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008874 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008875#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008876 first = NULL;
8877 next = xmlXPathNextPrecedingInternal;
8878 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008879 case AXIS_PRECEDING_SIBLING:
8880#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008881 xmlGenericError(xmlGenericErrorContext,
8882 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008883#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008884 first = NULL;
8885 next = xmlXPathNextPrecedingSibling;
8886 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008887 case AXIS_SELF:
8888#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008889 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008890#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008891 first = NULL;
8892 last = NULL;
8893 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00008894 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008895 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008896 }
8897 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008898 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008899
8900 nodelist = obj->nodesetval;
8901 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008902 xmlXPathFreeObject(obj);
8903 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8904 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008905 }
8906 addNode = xmlXPathNodeSetAddUnique;
8907 ret = NULL;
8908#ifdef DEBUG_STEP
8909 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008910 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008911 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008912 case NODE_TEST_NONE:
8913 xmlGenericError(xmlGenericErrorContext,
8914 " searching for none !!!\n");
8915 break;
8916 case NODE_TEST_TYPE:
8917 xmlGenericError(xmlGenericErrorContext,
8918 " searching for type %d\n", type);
8919 break;
8920 case NODE_TEST_PI:
8921 xmlGenericError(xmlGenericErrorContext,
8922 " searching for PI !!!\n");
8923 break;
8924 case NODE_TEST_ALL:
8925 xmlGenericError(xmlGenericErrorContext,
8926 " searching for *\n");
8927 break;
8928 case NODE_TEST_NS:
8929 xmlGenericError(xmlGenericErrorContext,
8930 " searching for namespace %s\n",
8931 prefix);
8932 break;
8933 case NODE_TEST_NAME:
8934 xmlGenericError(xmlGenericErrorContext,
8935 " searching for name %s\n", name);
8936 if (prefix != NULL)
8937 xmlGenericError(xmlGenericErrorContext,
8938 " with namespace %s\n", prefix);
8939 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008940 }
8941 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8942#endif
8943 /*
8944 * 2.3 Node Tests
8945 * - For the attribute axis, the principal node type is attribute.
8946 * - For the namespace axis, the principal node type is namespace.
8947 * - For other axes, the principal node type is element.
8948 *
8949 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008950 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008951 * select all element children of the context node
8952 */
8953 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008954 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008955 ctxt->context->node = nodelist->nodeTab[i];
8956
Daniel Veillardf06307e2001-07-03 10:35:50 +00008957 cur = NULL;
8958 list = xmlXPathNodeSetCreate(NULL);
8959 do {
8960 cur = next(ctxt, cur);
8961 if (cur == NULL)
8962 break;
8963 if ((first != NULL) && (*first == cur))
8964 break;
8965 if (((t % 256) == 0) &&
8966 (first != NULL) && (*first != NULL) &&
8967 (xmlXPathCmpNodes(*first, cur) >= 0))
8968 break;
8969 if ((last != NULL) && (*last == cur))
8970 break;
8971 if (((t % 256) == 0) &&
8972 (last != NULL) && (*last != NULL) &&
8973 (xmlXPathCmpNodes(cur, *last) >= 0))
8974 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008975 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008976#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008977 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
8978#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008979 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008980 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008981 ctxt->context->node = tmp;
8982 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008983 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008984 if ((cur->type == type) ||
8985 ((type == NODE_TYPE_NODE) &&
8986 ((cur->type == XML_DOCUMENT_NODE) ||
8987 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8988 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00008989 (cur->type == XML_NAMESPACE_DECL) ||
8990 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00008991 (cur->type == XML_PI_NODE) ||
8992 (cur->type == XML_COMMENT_NODE) ||
8993 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00008994 (cur->type == XML_TEXT_NODE))) ||
8995 ((type == NODE_TYPE_TEXT) &&
8996 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008997#ifdef DEBUG_STEP
8998 n++;
8999#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009000 addNode(list, cur);
9001 }
9002 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009003 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009004 if (cur->type == XML_PI_NODE) {
9005 if ((name != NULL) &&
9006 (!xmlStrEqual(name, cur->name)))
9007 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009008#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009009 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009010#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009011 addNode(list, cur);
9012 }
9013 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009014 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009015 if (axis == AXIS_ATTRIBUTE) {
9016 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009017#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009018 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009019#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009020 addNode(list, cur);
9021 }
9022 } else if (axis == AXIS_NAMESPACE) {
9023 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009024#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009025 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009026#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009027 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9028 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009029 }
9030 } else {
9031 if (cur->type == XML_ELEMENT_NODE) {
9032 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009033#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009034 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009035#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009036 addNode(list, cur);
9037 } else if ((cur->ns != NULL) &&
9038 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009039#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009040 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009041#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009042 addNode(list, cur);
9043 }
9044 }
9045 }
9046 break;
9047 case NODE_TEST_NS:{
9048 TODO;
9049 break;
9050 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009051 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009052 switch (cur->type) {
9053 case XML_ELEMENT_NODE:
9054 if (xmlStrEqual(name, cur->name)) {
9055 if (prefix == NULL) {
9056 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009057#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009058 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009059#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009060 addNode(list, cur);
9061 }
9062 } else {
9063 if ((cur->ns != NULL) &&
9064 (xmlStrEqual(URI,
9065 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009066#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009067 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009068#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009069 addNode(list, cur);
9070 }
9071 }
9072 }
9073 break;
9074 case XML_ATTRIBUTE_NODE:{
9075 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009076
Daniel Veillardf06307e2001-07-03 10:35:50 +00009077 if (xmlStrEqual(name, attr->name)) {
9078 if (prefix == NULL) {
9079 if ((attr->ns == NULL) ||
9080 (attr->ns->prefix == NULL)) {
9081#ifdef DEBUG_STEP
9082 n++;
9083#endif
9084 addNode(list,
9085 (xmlNodePtr) attr);
9086 }
9087 } else {
9088 if ((attr->ns != NULL) &&
9089 (xmlStrEqual(URI,
9090 attr->ns->
9091 href))) {
9092#ifdef DEBUG_STEP
9093 n++;
9094#endif
9095 addNode(list,
9096 (xmlNodePtr) attr);
9097 }
9098 }
9099 }
9100 break;
9101 }
9102 case XML_NAMESPACE_DECL:
9103 if (cur->type == XML_NAMESPACE_DECL) {
9104 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009105
Daniel Veillardf06307e2001-07-03 10:35:50 +00009106 if ((ns->prefix != NULL) && (name != NULL)
9107 && (xmlStrEqual(ns->prefix, name))) {
9108#ifdef DEBUG_STEP
9109 n++;
9110#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009111 xmlXPathNodeSetAddNs(list,
9112 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009113 }
9114 }
9115 break;
9116 default:
9117 break;
9118 }
9119 break;
9120 break;
9121 }
9122 } while (cur != NULL);
9123
9124 /*
9125 * If there is some predicate filtering do it now
9126 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009127 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009128 xmlXPathObjectPtr obj2;
9129
9130 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9131 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9132 CHECK_TYPE0(XPATH_NODESET);
9133 obj2 = valuePop(ctxt);
9134 list = obj2->nodesetval;
9135 obj2->nodesetval = NULL;
9136 xmlXPathFreeObject(obj2);
9137 }
9138 if (ret == NULL) {
9139 ret = list;
9140 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009141 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009142 xmlXPathFreeNodeSet(list);
9143 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009144 }
9145 ctxt->context->node = tmp;
9146#ifdef DEBUG_STEP
9147 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009148 "\nExamined %d nodes, found %d nodes at that step\n",
9149 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009150#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009151 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009152 if ((obj->boolval) && (obj->user != NULL)) {
9153 ctxt->value->boolval = 1;
9154 ctxt->value->user = obj->user;
9155 obj->user = NULL;
9156 obj->boolval = 0;
9157 }
9158 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009159 return(t);
9160}
9161
9162/**
9163 * xmlXPathNodeCollectAndTestNth:
9164 * @ctxt: the XPath Parser context
9165 * @op: the XPath precompiled step operation
9166 * @indx: the index to collect
9167 * @first: pointer to the first element in document order
9168 * @last: pointer to the last element in document order
9169 *
9170 * This is the function implementing a step: based on the current list
9171 * of nodes, it builds up a new list, looking at all nodes under that
9172 * axis and selecting them it also do the predicate filtering
9173 *
9174 * Pushes the new NodeSet resulting from the search.
9175 * Returns the number of node traversed
9176 */
9177static int
9178xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9179 xmlXPathStepOpPtr op, int indx,
9180 xmlNodePtr * first, xmlNodePtr * last)
9181{
9182 xmlXPathAxisVal axis = op->value;
9183 xmlXPathTestVal test = op->value2;
9184 xmlXPathTypeVal type = op->value3;
9185 const xmlChar *prefix = op->value4;
9186 const xmlChar *name = op->value5;
9187 const xmlChar *URI = NULL;
9188 int n = 0, t = 0;
9189
9190 int i;
9191 xmlNodeSetPtr list;
9192 xmlXPathTraversalFunction next = NULL;
9193 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9194 xmlNodePtr cur = NULL;
9195 xmlXPathObjectPtr obj;
9196 xmlNodeSetPtr nodelist;
9197 xmlNodePtr tmp;
9198
9199 CHECK_TYPE0(XPATH_NODESET);
9200 obj = valuePop(ctxt);
9201 addNode = xmlXPathNodeSetAdd;
9202 if (prefix != NULL) {
9203 URI = xmlXPathNsLookup(ctxt->context, prefix);
9204 if (URI == NULL)
9205 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9206 }
9207#ifdef DEBUG_STEP_NTH
9208 xmlGenericError(xmlGenericErrorContext, "new step : ");
9209 if (first != NULL) {
9210 if (*first != NULL)
9211 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9212 (*first)->name);
9213 else
9214 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9215 }
9216 if (last != NULL) {
9217 if (*last != NULL)
9218 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9219 (*last)->name);
9220 else
9221 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9222 }
9223#endif
9224 switch (axis) {
9225 case AXIS_ANCESTOR:
9226#ifdef DEBUG_STEP_NTH
9227 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9228#endif
9229 first = NULL;
9230 next = xmlXPathNextAncestor;
9231 break;
9232 case AXIS_ANCESTOR_OR_SELF:
9233#ifdef DEBUG_STEP_NTH
9234 xmlGenericError(xmlGenericErrorContext,
9235 "axis 'ancestors-or-self' ");
9236#endif
9237 first = NULL;
9238 next = xmlXPathNextAncestorOrSelf;
9239 break;
9240 case AXIS_ATTRIBUTE:
9241#ifdef DEBUG_STEP_NTH
9242 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9243#endif
9244 first = NULL;
9245 last = NULL;
9246 next = xmlXPathNextAttribute;
9247 break;
9248 case AXIS_CHILD:
9249#ifdef DEBUG_STEP_NTH
9250 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9251#endif
9252 last = NULL;
9253 next = xmlXPathNextChild;
9254 break;
9255 case AXIS_DESCENDANT:
9256#ifdef DEBUG_STEP_NTH
9257 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9258#endif
9259 last = NULL;
9260 next = xmlXPathNextDescendant;
9261 break;
9262 case AXIS_DESCENDANT_OR_SELF:
9263#ifdef DEBUG_STEP_NTH
9264 xmlGenericError(xmlGenericErrorContext,
9265 "axis 'descendant-or-self' ");
9266#endif
9267 last = NULL;
9268 next = xmlXPathNextDescendantOrSelf;
9269 break;
9270 case AXIS_FOLLOWING:
9271#ifdef DEBUG_STEP_NTH
9272 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9273#endif
9274 last = NULL;
9275 next = xmlXPathNextFollowing;
9276 break;
9277 case AXIS_FOLLOWING_SIBLING:
9278#ifdef DEBUG_STEP_NTH
9279 xmlGenericError(xmlGenericErrorContext,
9280 "axis 'following-siblings' ");
9281#endif
9282 last = NULL;
9283 next = xmlXPathNextFollowingSibling;
9284 break;
9285 case AXIS_NAMESPACE:
9286#ifdef DEBUG_STEP_NTH
9287 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9288#endif
9289 last = NULL;
9290 first = NULL;
9291 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9292 break;
9293 case AXIS_PARENT:
9294#ifdef DEBUG_STEP_NTH
9295 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9296#endif
9297 first = NULL;
9298 next = xmlXPathNextParent;
9299 break;
9300 case AXIS_PRECEDING:
9301#ifdef DEBUG_STEP_NTH
9302 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9303#endif
9304 first = NULL;
9305 next = xmlXPathNextPrecedingInternal;
9306 break;
9307 case AXIS_PRECEDING_SIBLING:
9308#ifdef DEBUG_STEP_NTH
9309 xmlGenericError(xmlGenericErrorContext,
9310 "axis 'preceding-sibling' ");
9311#endif
9312 first = NULL;
9313 next = xmlXPathNextPrecedingSibling;
9314 break;
9315 case AXIS_SELF:
9316#ifdef DEBUG_STEP_NTH
9317 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9318#endif
9319 first = NULL;
9320 last = NULL;
9321 next = xmlXPathNextSelf;
9322 break;
9323 }
9324 if (next == NULL)
9325 return(0);
9326
9327 nodelist = obj->nodesetval;
9328 if (nodelist == NULL) {
9329 xmlXPathFreeObject(obj);
9330 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9331 return(0);
9332 }
9333 addNode = xmlXPathNodeSetAddUnique;
9334#ifdef DEBUG_STEP_NTH
9335 xmlGenericError(xmlGenericErrorContext,
9336 " context contains %d nodes\n", nodelist->nodeNr);
9337 switch (test) {
9338 case NODE_TEST_NONE:
9339 xmlGenericError(xmlGenericErrorContext,
9340 " searching for none !!!\n");
9341 break;
9342 case NODE_TEST_TYPE:
9343 xmlGenericError(xmlGenericErrorContext,
9344 " searching for type %d\n", type);
9345 break;
9346 case NODE_TEST_PI:
9347 xmlGenericError(xmlGenericErrorContext,
9348 " searching for PI !!!\n");
9349 break;
9350 case NODE_TEST_ALL:
9351 xmlGenericError(xmlGenericErrorContext,
9352 " searching for *\n");
9353 break;
9354 case NODE_TEST_NS:
9355 xmlGenericError(xmlGenericErrorContext,
9356 " searching for namespace %s\n",
9357 prefix);
9358 break;
9359 case NODE_TEST_NAME:
9360 xmlGenericError(xmlGenericErrorContext,
9361 " searching for name %s\n", name);
9362 if (prefix != NULL)
9363 xmlGenericError(xmlGenericErrorContext,
9364 " with namespace %s\n", prefix);
9365 break;
9366 }
9367 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9368#endif
9369 /*
9370 * 2.3 Node Tests
9371 * - For the attribute axis, the principal node type is attribute.
9372 * - For the namespace axis, the principal node type is namespace.
9373 * - For other axes, the principal node type is element.
9374 *
9375 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009376 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009377 * select all element children of the context node
9378 */
9379 tmp = ctxt->context->node;
9380 list = xmlXPathNodeSetCreate(NULL);
9381 for (i = 0; i < nodelist->nodeNr; i++) {
9382 ctxt->context->node = nodelist->nodeTab[i];
9383
9384 cur = NULL;
9385 n = 0;
9386 do {
9387 cur = next(ctxt, cur);
9388 if (cur == NULL)
9389 break;
9390 if ((first != NULL) && (*first == cur))
9391 break;
9392 if (((t % 256) == 0) &&
9393 (first != NULL) && (*first != NULL) &&
9394 (xmlXPathCmpNodes(*first, cur) >= 0))
9395 break;
9396 if ((last != NULL) && (*last == cur))
9397 break;
9398 if (((t % 256) == 0) &&
9399 (last != NULL) && (*last != NULL) &&
9400 (xmlXPathCmpNodes(cur, *last) >= 0))
9401 break;
9402 t++;
9403 switch (test) {
9404 case NODE_TEST_NONE:
9405 ctxt->context->node = tmp;
9406 STRANGE return(0);
9407 case NODE_TEST_TYPE:
9408 if ((cur->type == type) ||
9409 ((type == NODE_TYPE_NODE) &&
9410 ((cur->type == XML_DOCUMENT_NODE) ||
9411 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9412 (cur->type == XML_ELEMENT_NODE) ||
9413 (cur->type == XML_PI_NODE) ||
9414 (cur->type == XML_COMMENT_NODE) ||
9415 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +00009416 (cur->type == XML_TEXT_NODE))) ||
9417 ((type == NODE_TYPE_TEXT) &&
9418 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009419 n++;
9420 if (n == indx)
9421 addNode(list, cur);
9422 }
9423 break;
9424 case NODE_TEST_PI:
9425 if (cur->type == XML_PI_NODE) {
9426 if ((name != NULL) &&
9427 (!xmlStrEqual(name, cur->name)))
9428 break;
9429 n++;
9430 if (n == indx)
9431 addNode(list, cur);
9432 }
9433 break;
9434 case NODE_TEST_ALL:
9435 if (axis == AXIS_ATTRIBUTE) {
9436 if (cur->type == XML_ATTRIBUTE_NODE) {
9437 n++;
9438 if (n == indx)
9439 addNode(list, cur);
9440 }
9441 } else if (axis == AXIS_NAMESPACE) {
9442 if (cur->type == XML_NAMESPACE_DECL) {
9443 n++;
9444 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009445 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9446 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009447 }
9448 } else {
9449 if (cur->type == XML_ELEMENT_NODE) {
9450 if (prefix == NULL) {
9451 n++;
9452 if (n == indx)
9453 addNode(list, cur);
9454 } else if ((cur->ns != NULL) &&
9455 (xmlStrEqual(URI, cur->ns->href))) {
9456 n++;
9457 if (n == indx)
9458 addNode(list, cur);
9459 }
9460 }
9461 }
9462 break;
9463 case NODE_TEST_NS:{
9464 TODO;
9465 break;
9466 }
9467 case NODE_TEST_NAME:
9468 switch (cur->type) {
9469 case XML_ELEMENT_NODE:
9470 if (xmlStrEqual(name, cur->name)) {
9471 if (prefix == NULL) {
9472 if (cur->ns == NULL) {
9473 n++;
9474 if (n == indx)
9475 addNode(list, cur);
9476 }
9477 } else {
9478 if ((cur->ns != NULL) &&
9479 (xmlStrEqual(URI,
9480 cur->ns->href))) {
9481 n++;
9482 if (n == indx)
9483 addNode(list, cur);
9484 }
9485 }
9486 }
9487 break;
9488 case XML_ATTRIBUTE_NODE:{
9489 xmlAttrPtr attr = (xmlAttrPtr) cur;
9490
9491 if (xmlStrEqual(name, attr->name)) {
9492 if (prefix == NULL) {
9493 if ((attr->ns == NULL) ||
9494 (attr->ns->prefix == NULL)) {
9495 n++;
9496 if (n == indx)
9497 addNode(list, cur);
9498 }
9499 } else {
9500 if ((attr->ns != NULL) &&
9501 (xmlStrEqual(URI,
9502 attr->ns->
9503 href))) {
9504 n++;
9505 if (n == indx)
9506 addNode(list, cur);
9507 }
9508 }
9509 }
9510 break;
9511 }
9512 case XML_NAMESPACE_DECL:
9513 if (cur->type == XML_NAMESPACE_DECL) {
9514 xmlNsPtr ns = (xmlNsPtr) cur;
9515
9516 if ((ns->prefix != NULL) && (name != NULL)
9517 && (xmlStrEqual(ns->prefix, name))) {
9518 n++;
9519 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009520 xmlXPathNodeSetAddNs(list,
9521 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009522 }
9523 }
9524 break;
9525 default:
9526 break;
9527 }
9528 break;
9529 break;
9530 }
9531 } while (n < indx);
9532 }
9533 ctxt->context->node = tmp;
9534#ifdef DEBUG_STEP_NTH
9535 xmlGenericError(xmlGenericErrorContext,
9536 "\nExamined %d nodes, found %d nodes at that step\n",
9537 t, list->nodeNr);
9538#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009539 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009540 if ((obj->boolval) && (obj->user != NULL)) {
9541 ctxt->value->boolval = 1;
9542 ctxt->value->user = obj->user;
9543 obj->user = NULL;
9544 obj->boolval = 0;
9545 }
9546 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009547 return(t);
9548}
9549
9550/**
9551 * xmlXPathCompOpEvalFirst:
9552 * @ctxt: the XPath parser context with the compiled expression
9553 * @op: an XPath compiled operation
9554 * @first: the first elem found so far
9555 *
9556 * Evaluate the Precompiled XPath operation searching only the first
9557 * element in document order
9558 *
9559 * Returns the number of examined objects.
9560 */
9561static int
9562xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9563 xmlXPathStepOpPtr op, xmlNodePtr * first)
9564{
9565 int total = 0, cur;
9566 xmlXPathCompExprPtr comp;
9567 xmlXPathObjectPtr arg1, arg2;
9568
Daniel Veillard556c6682001-10-06 09:59:51 +00009569 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009570 comp = ctxt->comp;
9571 switch (op->op) {
9572 case XPATH_OP_END:
9573 return (0);
9574 case XPATH_OP_UNION:
9575 total =
9576 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9577 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009578 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009579 if ((ctxt->value != NULL)
9580 && (ctxt->value->type == XPATH_NODESET)
9581 && (ctxt->value->nodesetval != NULL)
9582 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9583 /*
9584 * limit tree traversing to first node in the result
9585 */
9586 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9587 *first = ctxt->value->nodesetval->nodeTab[0];
9588 }
9589 cur =
9590 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9591 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009592 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009593 CHECK_TYPE0(XPATH_NODESET);
9594 arg2 = valuePop(ctxt);
9595
9596 CHECK_TYPE0(XPATH_NODESET);
9597 arg1 = valuePop(ctxt);
9598
9599 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9600 arg2->nodesetval);
9601 valuePush(ctxt, arg1);
9602 xmlXPathFreeObject(arg2);
9603 /* optimizer */
9604 if (total > cur)
9605 xmlXPathCompSwap(op);
9606 return (total + cur);
9607 case XPATH_OP_ROOT:
9608 xmlXPathRoot(ctxt);
9609 return (0);
9610 case XPATH_OP_NODE:
9611 if (op->ch1 != -1)
9612 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009613 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009614 if (op->ch2 != -1)
9615 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009616 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009617 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9618 return (total);
9619 case XPATH_OP_RESET:
9620 if (op->ch1 != -1)
9621 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009622 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009623 if (op->ch2 != -1)
9624 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009625 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009626 ctxt->context->node = NULL;
9627 return (total);
9628 case XPATH_OP_COLLECT:{
9629 if (op->ch1 == -1)
9630 return (total);
9631
9632 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009633 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009634
9635 /*
9636 * Optimization for [n] selection where n is a number
9637 */
9638 if ((op->ch2 != -1) &&
9639 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9640 (comp->steps[op->ch2].ch1 == -1) &&
9641 (comp->steps[op->ch2].ch2 != -1) &&
9642 (comp->steps[comp->steps[op->ch2].ch2].op ==
9643 XPATH_OP_VALUE)) {
9644 xmlXPathObjectPtr val;
9645
9646 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9647 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9648 int indx = (int) val->floatval;
9649
9650 if (val->floatval == (float) indx) {
9651 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9652 first, NULL);
9653 return (total);
9654 }
9655 }
9656 }
9657 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9658 return (total);
9659 }
9660 case XPATH_OP_VALUE:
9661 valuePush(ctxt,
9662 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9663 return (0);
9664 case XPATH_OP_SORT:
9665 if (op->ch1 != -1)
9666 total +=
9667 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9668 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009669 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009670 if ((ctxt->value != NULL)
9671 && (ctxt->value->type == XPATH_NODESET)
9672 && (ctxt->value->nodesetval != NULL))
9673 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9674 return (total);
9675 default:
9676 return (xmlXPathCompOpEval(ctxt, op));
9677 }
9678}
9679
9680/**
9681 * xmlXPathCompOpEvalLast:
9682 * @ctxt: the XPath parser context with the compiled expression
9683 * @op: an XPath compiled operation
9684 * @last: the last elem found so far
9685 *
9686 * Evaluate the Precompiled XPath operation searching only the last
9687 * element in document order
9688 *
9689 * Returns the number of node traversed
9690 */
9691static int
9692xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9693 xmlNodePtr * last)
9694{
9695 int total = 0, cur;
9696 xmlXPathCompExprPtr comp;
9697 xmlXPathObjectPtr arg1, arg2;
9698
Daniel Veillard556c6682001-10-06 09:59:51 +00009699 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009700 comp = ctxt->comp;
9701 switch (op->op) {
9702 case XPATH_OP_END:
9703 return (0);
9704 case XPATH_OP_UNION:
9705 total =
9706 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009707 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009708 if ((ctxt->value != NULL)
9709 && (ctxt->value->type == XPATH_NODESET)
9710 && (ctxt->value->nodesetval != NULL)
9711 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9712 /*
9713 * limit tree traversing to first node in the result
9714 */
9715 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9716 *last =
9717 ctxt->value->nodesetval->nodeTab[ctxt->value->
9718 nodesetval->nodeNr -
9719 1];
9720 }
9721 cur =
9722 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009723 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009724 if ((ctxt->value != NULL)
9725 && (ctxt->value->type == XPATH_NODESET)
9726 && (ctxt->value->nodesetval != NULL)
9727 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9728 }
9729 CHECK_TYPE0(XPATH_NODESET);
9730 arg2 = valuePop(ctxt);
9731
9732 CHECK_TYPE0(XPATH_NODESET);
9733 arg1 = valuePop(ctxt);
9734
9735 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9736 arg2->nodesetval);
9737 valuePush(ctxt, arg1);
9738 xmlXPathFreeObject(arg2);
9739 /* optimizer */
9740 if (total > cur)
9741 xmlXPathCompSwap(op);
9742 return (total + cur);
9743 case XPATH_OP_ROOT:
9744 xmlXPathRoot(ctxt);
9745 return (0);
9746 case XPATH_OP_NODE:
9747 if (op->ch1 != -1)
9748 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009749 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009750 if (op->ch2 != -1)
9751 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009752 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009753 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9754 return (total);
9755 case XPATH_OP_RESET:
9756 if (op->ch1 != -1)
9757 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009758 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009759 if (op->ch2 != -1)
9760 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009761 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009762 ctxt->context->node = NULL;
9763 return (total);
9764 case XPATH_OP_COLLECT:{
9765 if (op->ch1 == -1)
9766 return (0);
9767
9768 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009769 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009770
9771 /*
9772 * Optimization for [n] selection where n is a number
9773 */
9774 if ((op->ch2 != -1) &&
9775 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9776 (comp->steps[op->ch2].ch1 == -1) &&
9777 (comp->steps[op->ch2].ch2 != -1) &&
9778 (comp->steps[comp->steps[op->ch2].ch2].op ==
9779 XPATH_OP_VALUE)) {
9780 xmlXPathObjectPtr val;
9781
9782 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9783 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9784 int indx = (int) val->floatval;
9785
9786 if (val->floatval == (float) indx) {
9787 total +=
9788 xmlXPathNodeCollectAndTestNth(ctxt, op,
9789 indx, NULL,
9790 last);
9791 return (total);
9792 }
9793 }
9794 }
9795 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9796 return (total);
9797 }
9798 case XPATH_OP_VALUE:
9799 valuePush(ctxt,
9800 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9801 return (0);
9802 case XPATH_OP_SORT:
9803 if (op->ch1 != -1)
9804 total +=
9805 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9806 last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009807 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009808 if ((ctxt->value != NULL)
9809 && (ctxt->value->type == XPATH_NODESET)
9810 && (ctxt->value->nodesetval != NULL))
9811 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9812 return (total);
9813 default:
9814 return (xmlXPathCompOpEval(ctxt, op));
9815 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009816}
9817
Owen Taylor3473f882001-02-23 17:55:21 +00009818/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009819 * xmlXPathCompOpEval:
9820 * @ctxt: the XPath parser context with the compiled expression
9821 * @op: an XPath compiled operation
9822 *
9823 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009824 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009825 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009826static int
9827xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9828{
9829 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009830 int equal, ret;
9831 xmlXPathCompExprPtr comp;
9832 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009833 xmlNodePtr bak;
9834 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +00009835 int pp;
William M. Brack692092b2002-06-28 15:01:24 +00009836 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009837
Daniel Veillard556c6682001-10-06 09:59:51 +00009838 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009839 comp = ctxt->comp;
9840 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009841 case XPATH_OP_END:
9842 return (0);
9843 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009844 bakd = ctxt->context->doc;
9845 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009846 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009847 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009848 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009849 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009850 xmlXPathBooleanFunction(ctxt, 1);
9851 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9852 return (total);
9853 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009854 ctxt->context->doc = bakd;
9855 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009856 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009857 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009858 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009859 if (ctxt->error) {
9860 xmlXPathFreeObject(arg2);
9861 return(0);
9862 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009863 xmlXPathBooleanFunction(ctxt, 1);
9864 arg1 = valuePop(ctxt);
9865 arg1->boolval &= arg2->boolval;
9866 valuePush(ctxt, arg1);
9867 xmlXPathFreeObject(arg2);
9868 return (total);
9869 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009870 bakd = ctxt->context->doc;
9871 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009872 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009873 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009874 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009875 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009876 xmlXPathBooleanFunction(ctxt, 1);
9877 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9878 return (total);
9879 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009880 ctxt->context->doc = bakd;
9881 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009882 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009883 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009884 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009885 if (ctxt->error) {
9886 xmlXPathFreeObject(arg2);
9887 return(0);
9888 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009889 xmlXPathBooleanFunction(ctxt, 1);
9890 arg1 = valuePop(ctxt);
9891 arg1->boolval |= arg2->boolval;
9892 valuePush(ctxt, arg1);
9893 xmlXPathFreeObject(arg2);
9894 return (total);
9895 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009896 bakd = ctxt->context->doc;
9897 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009898 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009899 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009900 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009901 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009902 ctxt->context->doc = bakd;
9903 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009904 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009905 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009906 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009907 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +00009908 if (op->value)
9909 equal = xmlXPathEqualValues(ctxt);
9910 else
9911 equal = xmlXPathNotEqualValues(ctxt);
9912 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +00009913 return (total);
9914 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009915 bakd = ctxt->context->doc;
9916 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009917 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009918 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009919 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009920 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009921 ctxt->context->doc = bakd;
9922 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009923 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009924 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009925 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009926 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009927 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
9928 valuePush(ctxt, xmlXPathNewBoolean(ret));
9929 return (total);
9930 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009931 bakd = ctxt->context->doc;
9932 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009933 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009934 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009935 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009936 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009937 if (op->ch2 != -1) {
9938 ctxt->context->doc = bakd;
9939 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009940 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009941 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009942 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009943 }
Daniel Veillard556c6682001-10-06 09:59:51 +00009944 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009945 if (op->value == 0)
9946 xmlXPathSubValues(ctxt);
9947 else if (op->value == 1)
9948 xmlXPathAddValues(ctxt);
9949 else if (op->value == 2)
9950 xmlXPathValueFlipSign(ctxt);
9951 else if (op->value == 3) {
9952 CAST_TO_NUMBER;
9953 CHECK_TYPE0(XPATH_NUMBER);
9954 }
9955 return (total);
9956 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009957 bakd = ctxt->context->doc;
9958 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009959 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009960 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009961 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009962 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009963 ctxt->context->doc = bakd;
9964 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009965 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009966 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009967 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009968 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009969 if (op->value == 0)
9970 xmlXPathMultValues(ctxt);
9971 else if (op->value == 1)
9972 xmlXPathDivValues(ctxt);
9973 else if (op->value == 2)
9974 xmlXPathModValues(ctxt);
9975 return (total);
9976 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009977 bakd = ctxt->context->doc;
9978 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009979 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009980 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009981 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009982 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009983 ctxt->context->doc = bakd;
9984 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009985 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009986 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009987 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009988 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009989 CHECK_TYPE0(XPATH_NODESET);
9990 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009991
Daniel Veillardf06307e2001-07-03 10:35:50 +00009992 CHECK_TYPE0(XPATH_NODESET);
9993 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009994
Daniel Veillardf06307e2001-07-03 10:35:50 +00009995 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9996 arg2->nodesetval);
9997 valuePush(ctxt, arg1);
9998 xmlXPathFreeObject(arg2);
9999 return (total);
10000 case XPATH_OP_ROOT:
10001 xmlXPathRoot(ctxt);
10002 return (total);
10003 case XPATH_OP_NODE:
10004 if (op->ch1 != -1)
10005 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010006 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010007 if (op->ch2 != -1)
10008 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010009 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010010 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10011 return (total);
10012 case XPATH_OP_RESET:
10013 if (op->ch1 != -1)
10014 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010015 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010016 if (op->ch2 != -1)
10017 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010018 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010019 ctxt->context->node = NULL;
10020 return (total);
10021 case XPATH_OP_COLLECT:{
10022 if (op->ch1 == -1)
10023 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010024
Daniel Veillardf06307e2001-07-03 10:35:50 +000010025 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010026 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010027
Daniel Veillardf06307e2001-07-03 10:35:50 +000010028 /*
10029 * Optimization for [n] selection where n is a number
10030 */
10031 if ((op->ch2 != -1) &&
10032 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10033 (comp->steps[op->ch2].ch1 == -1) &&
10034 (comp->steps[op->ch2].ch2 != -1) &&
10035 (comp->steps[comp->steps[op->ch2].ch2].op ==
10036 XPATH_OP_VALUE)) {
10037 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +000010038
Daniel Veillardf06307e2001-07-03 10:35:50 +000010039 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10040 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10041 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010042
Daniel Veillardf06307e2001-07-03 10:35:50 +000010043 if (val->floatval == (float) indx) {
10044 total +=
10045 xmlXPathNodeCollectAndTestNth(ctxt, op,
10046 indx, NULL,
10047 NULL);
10048 return (total);
10049 }
10050 }
10051 }
10052 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
10053 return (total);
10054 }
10055 case XPATH_OP_VALUE:
10056 valuePush(ctxt,
10057 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10058 return (total);
10059 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000010060 xmlXPathObjectPtr val;
10061
Daniel Veillardf06307e2001-07-03 10:35:50 +000010062 if (op->ch1 != -1)
10063 total +=
10064 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010065 if (op->value5 == NULL) {
10066 val = xmlXPathVariableLookup(ctxt->context, op->value4);
10067 if (val == NULL) {
10068 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10069 return(0);
10070 }
10071 valuePush(ctxt, val);
10072 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010073 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010074
Daniel Veillardf06307e2001-07-03 10:35:50 +000010075 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10076 if (URI == NULL) {
10077 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010078 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010079 op->value4, op->value5);
10080 return (total);
10081 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010082 val = xmlXPathVariableLookupNS(ctxt->context,
10083 op->value4, URI);
10084 if (val == NULL) {
10085 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10086 return(0);
10087 }
10088 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010089 }
10090 return (total);
10091 }
10092 case XPATH_OP_FUNCTION:{
10093 xmlXPathFunction func;
10094 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000010095 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010096
10097 if (op->ch1 != -1)
10098 total +=
10099 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010100 if (ctxt->valueNr < op->value) {
10101 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010102 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010103 ctxt->error = XPATH_INVALID_OPERAND;
10104 return (total);
10105 }
10106 for (i = 0; i < op->value; i++)
10107 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10108 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010109 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010110 ctxt->error = XPATH_INVALID_OPERAND;
10111 return (total);
10112 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010113 if (op->cache != NULL)
10114 func = (xmlXPathFunction) op->cache;
10115 else {
10116 const xmlChar *URI = NULL;
10117
10118 if (op->value5 == NULL)
10119 func =
10120 xmlXPathFunctionLookup(ctxt->context,
10121 op->value4);
10122 else {
10123 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10124 if (URI == NULL) {
10125 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010126 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010127 op->value4, op->value5);
10128 return (total);
10129 }
10130 func = xmlXPathFunctionLookupNS(ctxt->context,
10131 op->value4, URI);
10132 }
10133 if (func == NULL) {
10134 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010135 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010136 op->value4);
10137 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010138 }
10139 op->cache = (void *) func;
10140 op->cacheURI = (void *) URI;
10141 }
10142 oldFunc = ctxt->context->function;
10143 oldFuncURI = ctxt->context->functionURI;
10144 ctxt->context->function = op->value4;
10145 ctxt->context->functionURI = op->cacheURI;
10146 func(ctxt, op->value);
10147 ctxt->context->function = oldFunc;
10148 ctxt->context->functionURI = oldFuncURI;
10149 return (total);
10150 }
10151 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000010152 bakd = ctxt->context->doc;
10153 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010154 if (op->ch1 != -1)
10155 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010156 ctxt->context->doc = bakd;
10157 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010158 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010159 if (op->ch2 != -1)
10160 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010161 ctxt->context->doc = bakd;
10162 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010163 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010164 return (total);
10165 case XPATH_OP_PREDICATE:
10166 case XPATH_OP_FILTER:{
10167 xmlXPathObjectPtr res;
10168 xmlXPathObjectPtr obj, tmp;
10169 xmlNodeSetPtr newset = NULL;
10170 xmlNodeSetPtr oldset;
10171 xmlNodePtr oldnode;
10172 int i;
10173
10174 /*
10175 * Optimization for ()[1] selection i.e. the first elem
10176 */
10177 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10178 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10179 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10180 xmlXPathObjectPtr val;
10181
10182 val = comp->steps[op->ch2].value4;
10183 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10184 (val->floatval == 1.0)) {
10185 xmlNodePtr first = NULL;
10186
10187 total +=
10188 xmlXPathCompOpEvalFirst(ctxt,
10189 &comp->steps[op->ch1],
10190 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010191 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010192 /*
10193 * The nodeset should be in document order,
10194 * Keep only the first value
10195 */
10196 if ((ctxt->value != NULL) &&
10197 (ctxt->value->type == XPATH_NODESET) &&
10198 (ctxt->value->nodesetval != NULL) &&
10199 (ctxt->value->nodesetval->nodeNr > 1))
10200 ctxt->value->nodesetval->nodeNr = 1;
10201 return (total);
10202 }
10203 }
10204 /*
10205 * Optimization for ()[last()] selection i.e. the last elem
10206 */
10207 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10208 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10209 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10210 int f = comp->steps[op->ch2].ch1;
10211
10212 if ((f != -1) &&
10213 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10214 (comp->steps[f].value5 == NULL) &&
10215 (comp->steps[f].value == 0) &&
10216 (comp->steps[f].value4 != NULL) &&
10217 (xmlStrEqual
10218 (comp->steps[f].value4, BAD_CAST "last"))) {
10219 xmlNodePtr last = NULL;
10220
10221 total +=
10222 xmlXPathCompOpEvalLast(ctxt,
10223 &comp->steps[op->ch1],
10224 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010225 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010226 /*
10227 * The nodeset should be in document order,
10228 * Keep only the last value
10229 */
10230 if ((ctxt->value != NULL) &&
10231 (ctxt->value->type == XPATH_NODESET) &&
10232 (ctxt->value->nodesetval != NULL) &&
10233 (ctxt->value->nodesetval->nodeTab != NULL) &&
10234 (ctxt->value->nodesetval->nodeNr > 1)) {
10235 ctxt->value->nodesetval->nodeTab[0] =
10236 ctxt->value->nodesetval->nodeTab[ctxt->
10237 value->
10238 nodesetval->
10239 nodeNr -
10240 1];
10241 ctxt->value->nodesetval->nodeNr = 1;
10242 }
10243 return (total);
10244 }
10245 }
10246
10247 if (op->ch1 != -1)
10248 total +=
10249 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010250 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010251 if (op->ch2 == -1)
10252 return (total);
10253 if (ctxt->value == NULL)
10254 return (total);
10255
10256 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010257
10258#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010259 /*
10260 * Hum are we filtering the result of an XPointer expression
10261 */
10262 if (ctxt->value->type == XPATH_LOCATIONSET) {
10263 xmlLocationSetPtr newlocset = NULL;
10264 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010265
Daniel Veillardf06307e2001-07-03 10:35:50 +000010266 /*
10267 * Extract the old locset, and then evaluate the result of the
10268 * expression for all the element in the locset. use it to grow
10269 * up a new locset.
10270 */
10271 CHECK_TYPE0(XPATH_LOCATIONSET);
10272 obj = valuePop(ctxt);
10273 oldlocset = obj->user;
10274 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010275
Daniel Veillardf06307e2001-07-03 10:35:50 +000010276 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10277 ctxt->context->contextSize = 0;
10278 ctxt->context->proximityPosition = 0;
10279 if (op->ch2 != -1)
10280 total +=
10281 xmlXPathCompOpEval(ctxt,
10282 &comp->steps[op->ch2]);
10283 res = valuePop(ctxt);
10284 if (res != NULL)
10285 xmlXPathFreeObject(res);
10286 valuePush(ctxt, obj);
10287 CHECK_ERROR0;
10288 return (total);
10289 }
10290 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010291
Daniel Veillardf06307e2001-07-03 10:35:50 +000010292 for (i = 0; i < oldlocset->locNr; i++) {
10293 /*
10294 * Run the evaluation with a node list made of a
10295 * single item in the nodelocset.
10296 */
10297 ctxt->context->node = oldlocset->locTab[i]->user;
10298 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10299 valuePush(ctxt, tmp);
10300 ctxt->context->contextSize = oldlocset->locNr;
10301 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010302
Daniel Veillardf06307e2001-07-03 10:35:50 +000010303 if (op->ch2 != -1)
10304 total +=
10305 xmlXPathCompOpEval(ctxt,
10306 &comp->steps[op->ch2]);
10307 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010308
Daniel Veillardf06307e2001-07-03 10:35:50 +000010309 /*
10310 * The result of the evaluation need to be tested to
10311 * decided whether the filter succeeded or not
10312 */
10313 res = valuePop(ctxt);
10314 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10315 xmlXPtrLocationSetAdd(newlocset,
10316 xmlXPathObjectCopy
10317 (oldlocset->locTab[i]));
10318 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010319
Daniel Veillardf06307e2001-07-03 10:35:50 +000010320 /*
10321 * Cleanup
10322 */
10323 if (res != NULL)
10324 xmlXPathFreeObject(res);
10325 if (ctxt->value == tmp) {
10326 res = valuePop(ctxt);
10327 xmlXPathFreeObject(res);
10328 }
10329
10330 ctxt->context->node = NULL;
10331 }
10332
10333 /*
10334 * The result is used as the new evaluation locset.
10335 */
10336 xmlXPathFreeObject(obj);
10337 ctxt->context->node = NULL;
10338 ctxt->context->contextSize = -1;
10339 ctxt->context->proximityPosition = -1;
10340 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10341 ctxt->context->node = oldnode;
10342 return (total);
10343 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010344#endif /* LIBXML_XPTR_ENABLED */
10345
Daniel Veillardf06307e2001-07-03 10:35:50 +000010346 /*
10347 * Extract the old set, and then evaluate the result of the
10348 * expression for all the element in the set. use it to grow
10349 * up a new set.
10350 */
10351 CHECK_TYPE0(XPATH_NODESET);
10352 obj = valuePop(ctxt);
10353 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010354
Daniel Veillardf06307e2001-07-03 10:35:50 +000010355 oldnode = ctxt->context->node;
10356 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010357
Daniel Veillardf06307e2001-07-03 10:35:50 +000010358 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10359 ctxt->context->contextSize = 0;
10360 ctxt->context->proximityPosition = 0;
10361 if (op->ch2 != -1)
10362 total +=
10363 xmlXPathCompOpEval(ctxt,
10364 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010365 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010366 res = valuePop(ctxt);
10367 if (res != NULL)
10368 xmlXPathFreeObject(res);
10369 valuePush(ctxt, obj);
10370 ctxt->context->node = oldnode;
10371 CHECK_ERROR0;
10372 } else {
10373 /*
10374 * Initialize the new set.
10375 */
10376 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010377
Daniel Veillardf06307e2001-07-03 10:35:50 +000010378 for (i = 0; i < oldset->nodeNr; i++) {
10379 /*
10380 * Run the evaluation with a node list made of
10381 * a single item in the nodeset.
10382 */
10383 ctxt->context->node = oldset->nodeTab[i];
10384 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10385 valuePush(ctxt, tmp);
10386 ctxt->context->contextSize = oldset->nodeNr;
10387 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010388
Daniel Veillardf06307e2001-07-03 10:35:50 +000010389 if (op->ch2 != -1)
10390 total +=
10391 xmlXPathCompOpEval(ctxt,
10392 &comp->steps[op->ch2]);
10393 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010394
Daniel Veillardf06307e2001-07-03 10:35:50 +000010395 /*
10396 * The result of the evaluation need to be tested to
10397 * decided whether the filter succeeded or not
10398 */
10399 res = valuePop(ctxt);
10400 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10401 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10402 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010403
Daniel Veillardf06307e2001-07-03 10:35:50 +000010404 /*
10405 * Cleanup
10406 */
10407 if (res != NULL)
10408 xmlXPathFreeObject(res);
10409 if (ctxt->value == tmp) {
10410 res = valuePop(ctxt);
10411 xmlXPathFreeObject(res);
10412 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010413
Daniel Veillardf06307e2001-07-03 10:35:50 +000010414 ctxt->context->node = NULL;
10415 }
10416
10417 /*
10418 * The result is used as the new evaluation set.
10419 */
10420 xmlXPathFreeObject(obj);
10421 ctxt->context->node = NULL;
10422 ctxt->context->contextSize = -1;
10423 ctxt->context->proximityPosition = -1;
10424 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10425 }
10426 ctxt->context->node = oldnode;
10427 return (total);
10428 }
10429 case XPATH_OP_SORT:
10430 if (op->ch1 != -1)
10431 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010432 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010433 if ((ctxt->value != NULL) &&
10434 (ctxt->value->type == XPATH_NODESET) &&
10435 (ctxt->value->nodesetval != NULL))
10436 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10437 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010438#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010439 case XPATH_OP_RANGETO:{
10440 xmlXPathObjectPtr range;
10441 xmlXPathObjectPtr res, obj;
10442 xmlXPathObjectPtr tmp;
10443 xmlLocationSetPtr newset = NULL;
10444 xmlNodeSetPtr oldset;
10445 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010446
Daniel Veillardf06307e2001-07-03 10:35:50 +000010447 if (op->ch1 != -1)
10448 total +=
10449 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10450 if (op->ch2 == -1)
10451 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010452
Daniel Veillardf06307e2001-07-03 10:35:50 +000010453 CHECK_TYPE0(XPATH_NODESET);
10454 obj = valuePop(ctxt);
10455 oldset = obj->nodesetval;
10456 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010457
Daniel Veillardf06307e2001-07-03 10:35:50 +000010458 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010459
Daniel Veillardf06307e2001-07-03 10:35:50 +000010460 if (oldset != NULL) {
10461 for (i = 0; i < oldset->nodeNr; i++) {
10462 /*
10463 * Run the evaluation with a node list made of a single item
10464 * in the nodeset.
10465 */
10466 ctxt->context->node = oldset->nodeTab[i];
10467 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10468 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010469
Daniel Veillardf06307e2001-07-03 10:35:50 +000010470 if (op->ch2 != -1)
10471 total +=
10472 xmlXPathCompOpEval(ctxt,
10473 &comp->steps[op->ch2]);
10474 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010475
Daniel Veillardf06307e2001-07-03 10:35:50 +000010476 /*
10477 * The result of the evaluation need to be tested to
10478 * decided whether the filter succeeded or not
10479 */
10480 res = valuePop(ctxt);
10481 range =
10482 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10483 res);
10484 if (range != NULL) {
10485 xmlXPtrLocationSetAdd(newset, range);
10486 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010487
Daniel Veillardf06307e2001-07-03 10:35:50 +000010488 /*
10489 * Cleanup
10490 */
10491 if (res != NULL)
10492 xmlXPathFreeObject(res);
10493 if (ctxt->value == tmp) {
10494 res = valuePop(ctxt);
10495 xmlXPathFreeObject(res);
10496 }
10497
10498 ctxt->context->node = NULL;
10499 }
10500 }
10501
10502 /*
10503 * The result is used as the new evaluation set.
10504 */
10505 xmlXPathFreeObject(obj);
10506 ctxt->context->node = NULL;
10507 ctxt->context->contextSize = -1;
10508 ctxt->context->proximityPosition = -1;
10509 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
10510 return (total);
10511 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010512#endif /* LIBXML_XPTR_ENABLED */
10513 }
10514 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010515 "XPath: unknown precompiled operation %d\n", op->op);
10516 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010517}
10518
10519/**
10520 * xmlXPathRunEval:
10521 * @ctxt: the XPath parser context with the compiled expression
10522 *
10523 * Evaluate the Precompiled XPath expression in the given context.
10524 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010525static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010526xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10527 xmlXPathCompExprPtr comp;
10528
10529 if ((ctxt == NULL) || (ctxt->comp == NULL))
10530 return;
10531
10532 if (ctxt->valueTab == NULL) {
10533 /* Allocate the value stack */
10534 ctxt->valueTab = (xmlXPathObjectPtr *)
10535 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10536 if (ctxt->valueTab == NULL) {
10537 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010538 }
10539 ctxt->valueNr = 0;
10540 ctxt->valueMax = 10;
10541 ctxt->value = NULL;
10542 }
10543 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000010544 if(comp->last < 0) {
10545 xmlGenericError(xmlGenericErrorContext,
10546 "xmlXPathRunEval: last is less than zero\n");
10547 return;
10548 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010549 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10550}
10551
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010552/************************************************************************
10553 * *
10554 * Public interfaces *
10555 * *
10556 ************************************************************************/
10557
10558/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010559 * xmlXPathEvalPredicate:
10560 * @ctxt: the XPath context
10561 * @res: the Predicate Expression evaluation result
10562 *
10563 * Evaluate a predicate result for the current node.
10564 * A PredicateExpr is evaluated by evaluating the Expr and converting
10565 * the result to a boolean. If the result is a number, the result will
10566 * be converted to true if the number is equal to the position of the
10567 * context node in the context node list (as returned by the position
10568 * function) and will be converted to false otherwise; if the result
10569 * is not a number, then the result will be converted as if by a call
10570 * to the boolean function.
10571 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010572 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010573 */
10574int
10575xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
10576 if (res == NULL) return(0);
10577 switch (res->type) {
10578 case XPATH_BOOLEAN:
10579 return(res->boolval);
10580 case XPATH_NUMBER:
10581 return(res->floatval == ctxt->proximityPosition);
10582 case XPATH_NODESET:
10583 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010584 if (res->nodesetval == NULL)
10585 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010586 return(res->nodesetval->nodeNr != 0);
10587 case XPATH_STRING:
10588 return((res->stringval != NULL) &&
10589 (xmlStrlen(res->stringval) != 0));
10590 default:
10591 STRANGE
10592 }
10593 return(0);
10594}
10595
10596/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010597 * xmlXPathEvaluatePredicateResult:
10598 * @ctxt: the XPath Parser context
10599 * @res: the Predicate Expression evaluation result
10600 *
10601 * Evaluate a predicate result for the current node.
10602 * A PredicateExpr is evaluated by evaluating the Expr and converting
10603 * the result to a boolean. If the result is a number, the result will
10604 * be converted to true if the number is equal to the position of the
10605 * context node in the context node list (as returned by the position
10606 * function) and will be converted to false otherwise; if the result
10607 * is not a number, then the result will be converted as if by a call
10608 * to the boolean function.
10609 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010610 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010611 */
10612int
10613xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10614 xmlXPathObjectPtr res) {
10615 if (res == NULL) return(0);
10616 switch (res->type) {
10617 case XPATH_BOOLEAN:
10618 return(res->boolval);
10619 case XPATH_NUMBER:
10620 return(res->floatval == ctxt->context->proximityPosition);
10621 case XPATH_NODESET:
10622 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000010623 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000010624 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010625 return(res->nodesetval->nodeNr != 0);
10626 case XPATH_STRING:
10627 return((res->stringval != NULL) &&
10628 (xmlStrlen(res->stringval) != 0));
10629 default:
10630 STRANGE
10631 }
10632 return(0);
10633}
10634
10635/**
10636 * xmlXPathCompile:
10637 * @str: the XPath expression
10638 *
10639 * Compile an XPath expression
10640 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000010641 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010642 * the caller has to free the object.
10643 */
10644xmlXPathCompExprPtr
10645xmlXPathCompile(const xmlChar *str) {
10646 xmlXPathParserContextPtr ctxt;
10647 xmlXPathCompExprPtr comp;
10648
10649 xmlXPathInit();
10650
10651 ctxt = xmlXPathNewParserContext(str, NULL);
10652 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010653
Daniel Veillard40af6492001-04-22 08:50:55 +000010654 if (*ctxt->cur != 0) {
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010655 /*
10656 * aleksey: in some cases this line prints *second* error message
10657 * (see bug #78858) and probably this should be fixed.
10658 * However, we are not sure that all error messages are printed
10659 * out in other places. It's not critical so we leave it as-is for now
10660 */
Daniel Veillard40af6492001-04-22 08:50:55 +000010661 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10662 comp = NULL;
10663 } else {
10664 comp = ctxt->comp;
10665 ctxt->comp = NULL;
10666 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010667 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010668 if (comp != NULL) {
Daniel Veillardceb09b92002-10-04 11:46:37 +000010669 comp->expr = xmlStrdup(str);
10670#ifdef DEBUG_EVAL_COUNTS
Daniel Veillardf06307e2001-07-03 10:35:50 +000010671 comp->string = xmlStrdup(str);
10672 comp->nb = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010673#endif
Daniel Veillardceb09b92002-10-04 11:46:37 +000010674 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010675 return(comp);
10676}
10677
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010678/**
10679 * xmlXPathCompiledEval:
10680 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000010681 * @ctx: the XPath context
10682 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010683 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000010684 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010685 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000010686 * the caller has to free the object.
10687 */
10688xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010689xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000010690 xmlXPathParserContextPtr ctxt;
10691 xmlXPathObjectPtr res, tmp, init = NULL;
10692 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000010693#ifndef LIBXML_THREAD_ENABLED
10694 static int reentance = 0;
10695#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010696
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010697 if ((comp == NULL) || (ctx == NULL))
10698 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010699 xmlXPathInit();
10700
10701 CHECK_CONTEXT(ctx)
10702
Daniel Veillard81463942001-10-16 12:34:39 +000010703#ifndef LIBXML_THREAD_ENABLED
10704 reentance++;
10705 if (reentance > 1)
10706 xmlXPathDisableOptimizer = 1;
10707#endif
10708
Daniel Veillardf06307e2001-07-03 10:35:50 +000010709#ifdef DEBUG_EVAL_COUNTS
10710 comp->nb++;
10711 if ((comp->string != NULL) && (comp->nb > 100)) {
10712 fprintf(stderr, "100 x %s\n", comp->string);
10713 comp->nb = 0;
10714 }
10715#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010716 ctxt = xmlXPathCompParserContext(comp, ctx);
10717 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010718
10719 if (ctxt->value == NULL) {
10720 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010721 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000010722 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000010723 } else {
10724 res = valuePop(ctxt);
10725 }
10726
Daniel Veillardf06307e2001-07-03 10:35:50 +000010727
Owen Taylor3473f882001-02-23 17:55:21 +000010728 do {
10729 tmp = valuePop(ctxt);
10730 if (tmp != NULL) {
10731 if (tmp != init)
10732 stack++;
10733 xmlXPathFreeObject(tmp);
10734 }
10735 } while (tmp != NULL);
10736 if ((stack != 0) && (res != NULL)) {
10737 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010738 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000010739 stack);
10740 }
10741 if (ctxt->error != XPATH_EXPRESSION_OK) {
10742 xmlXPathFreeObject(res);
10743 res = NULL;
10744 }
10745
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010746
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010747 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010748 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000010749#ifndef LIBXML_THREAD_ENABLED
10750 reentance--;
10751#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010752 return(res);
10753}
10754
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010755/**
10756 * xmlXPathEvalExpr:
10757 * @ctxt: the XPath Parser context
10758 *
10759 * Parse and evaluate an XPath expression in the given context,
10760 * then push the result on the context stack
10761 */
10762void
10763xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
10764 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010765 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010766 xmlXPathRunEval(ctxt);
10767}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010768
10769/**
10770 * xmlXPathEval:
10771 * @str: the XPath expression
10772 * @ctx: the XPath context
10773 *
10774 * Evaluate the XPath Location Path in the given context.
10775 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010776 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010777 * the caller has to free the object.
10778 */
10779xmlXPathObjectPtr
10780xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
10781 xmlXPathParserContextPtr ctxt;
10782 xmlXPathObjectPtr res, tmp, init = NULL;
10783 int stack = 0;
10784
10785 xmlXPathInit();
10786
10787 CHECK_CONTEXT(ctx)
10788
10789 ctxt = xmlXPathNewParserContext(str, ctx);
10790 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010791
10792 if (ctxt->value == NULL) {
10793 xmlGenericError(xmlGenericErrorContext,
10794 "xmlXPathEval: evaluation failed\n");
10795 res = NULL;
10796 } else if (*ctxt->cur != 0) {
10797 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10798 res = NULL;
10799 } else {
10800 res = valuePop(ctxt);
10801 }
10802
10803 do {
10804 tmp = valuePop(ctxt);
10805 if (tmp != NULL) {
10806 if (tmp != init)
10807 stack++;
10808 xmlXPathFreeObject(tmp);
10809 }
10810 } while (tmp != NULL);
10811 if ((stack != 0) && (res != NULL)) {
10812 xmlGenericError(xmlGenericErrorContext,
10813 "xmlXPathEval: %d object left on the stack\n",
10814 stack);
10815 }
10816 if (ctxt->error != XPATH_EXPRESSION_OK) {
10817 xmlXPathFreeObject(res);
10818 res = NULL;
10819 }
10820
Owen Taylor3473f882001-02-23 17:55:21 +000010821 xmlXPathFreeParserContext(ctxt);
10822 return(res);
10823}
10824
10825/**
10826 * xmlXPathEvalExpression:
10827 * @str: the XPath expression
10828 * @ctxt: the XPath context
10829 *
10830 * Evaluate the XPath expression in the given context.
10831 *
10832 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
10833 * the caller has to free the object.
10834 */
10835xmlXPathObjectPtr
10836xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
10837 xmlXPathParserContextPtr pctxt;
10838 xmlXPathObjectPtr res, tmp;
10839 int stack = 0;
10840
10841 xmlXPathInit();
10842
10843 CHECK_CONTEXT(ctxt)
10844
10845 pctxt = xmlXPathNewParserContext(str, ctxt);
10846 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010847
10848 if (*pctxt->cur != 0) {
10849 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10850 res = NULL;
10851 } else {
10852 res = valuePop(pctxt);
10853 }
10854 do {
10855 tmp = valuePop(pctxt);
10856 if (tmp != NULL) {
10857 xmlXPathFreeObject(tmp);
10858 stack++;
10859 }
10860 } while (tmp != NULL);
10861 if ((stack != 0) && (res != NULL)) {
10862 xmlGenericError(xmlGenericErrorContext,
10863 "xmlXPathEvalExpression: %d object left on the stack\n",
10864 stack);
10865 }
10866 xmlXPathFreeParserContext(pctxt);
10867 return(res);
10868}
10869
Daniel Veillard42766c02002-08-22 20:52:17 +000010870/************************************************************************
10871 * *
10872 * Extra functions not pertaining to the XPath spec *
10873 * *
10874 ************************************************************************/
10875/**
10876 * xmlXPathEscapeUriFunction:
10877 * @ctxt: the XPath Parser context
10878 * @nargs: the number of arguments
10879 *
10880 * Implement the escape-uri() XPath function
10881 * string escape-uri(string $str, bool $escape-reserved)
10882 *
10883 * This function applies the URI escaping rules defined in section 2 of [RFC
10884 * 2396] to the string supplied as $uri-part, which typically represents all
10885 * or part of a URI. The effect of the function is to replace any special
10886 * character in the string by an escape sequence of the form %xx%yy...,
10887 * where xxyy... is the hexadecimal representation of the octets used to
10888 * represent the character in UTF-8.
10889 *
10890 * The set of characters that are escaped depends on the setting of the
10891 * boolean argument $escape-reserved.
10892 *
10893 * If $escape-reserved is true, all characters are escaped other than lower
10894 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
10895 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
10896 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
10897 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
10898 * A-F).
10899 *
10900 * If $escape-reserved is false, the behavior differs in that characters
10901 * referred to in [RFC 2396] as reserved characters are not escaped. These
10902 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
10903 *
10904 * [RFC 2396] does not define whether escaped URIs should use lower case or
10905 * upper case for hexadecimal digits. To ensure that escaped URIs can be
10906 * compared using string comparison functions, this function must always use
10907 * the upper-case letters A-F.
10908 *
10909 * Generally, $escape-reserved should be set to true when escaping a string
10910 * that is to form a single part of a URI, and to false when escaping an
10911 * entire URI or URI reference.
10912 *
10913 * In the case of non-ascii characters, the string is encoded according to
10914 * utf-8 and then converted according to RFC 2396.
10915 *
10916 * Examples
10917 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
10918 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
10919 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
10920 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
10921 *
10922 */
Daniel Veillard118aed72002-09-24 14:13:13 +000010923static void
Daniel Veillard42766c02002-08-22 20:52:17 +000010924xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
10925 xmlXPathObjectPtr str;
10926 int escape_reserved;
10927 xmlBufferPtr target;
10928 xmlChar *cptr;
10929 xmlChar escape[4];
10930
10931 CHECK_ARITY(2);
10932
10933 escape_reserved = xmlXPathPopBoolean(ctxt);
10934
10935 CAST_TO_STRING;
10936 str = valuePop(ctxt);
10937
10938 target = xmlBufferCreate();
10939
10940 escape[0] = '%';
10941 escape[3] = 0;
10942
10943 if (target) {
10944 for (cptr = str->stringval; *cptr; cptr++) {
10945 if ((*cptr >= 'A' && *cptr <= 'Z') ||
10946 (*cptr >= 'a' && *cptr <= 'z') ||
10947 (*cptr >= '0' && *cptr <= '9') ||
10948 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
10949 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
10950 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
10951 (*cptr == '%' &&
10952 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
10953 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
10954 (cptr[1] >= '0' && cptr[1] <= '9')) &&
10955 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
10956 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
10957 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
10958 (!escape_reserved &&
10959 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
10960 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
10961 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
10962 *cptr == ','))) {
10963 xmlBufferAdd(target, cptr, 1);
10964 } else {
10965 if ((*cptr >> 4) < 10)
10966 escape[1] = '0' + (*cptr >> 4);
10967 else
10968 escape[1] = 'A' - 10 + (*cptr >> 4);
10969 if ((*cptr & 0xF) < 10)
10970 escape[2] = '0' + (*cptr & 0xF);
10971 else
10972 escape[2] = 'A' - 10 + (*cptr & 0xF);
10973
10974 xmlBufferAdd(target, &escape[0], 3);
10975 }
10976 }
10977 }
10978 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
10979 xmlBufferFree(target);
10980 xmlXPathFreeObject(str);
10981}
10982
Owen Taylor3473f882001-02-23 17:55:21 +000010983/**
10984 * xmlXPathRegisterAllFunctions:
10985 * @ctxt: the XPath context
10986 *
10987 * Registers all default XPath functions in this context
10988 */
10989void
10990xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
10991{
10992 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
10993 xmlXPathBooleanFunction);
10994 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
10995 xmlXPathCeilingFunction);
10996 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
10997 xmlXPathCountFunction);
10998 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
10999 xmlXPathConcatFunction);
11000 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
11001 xmlXPathContainsFunction);
11002 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
11003 xmlXPathIdFunction);
11004 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
11005 xmlXPathFalseFunction);
11006 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
11007 xmlXPathFloorFunction);
11008 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
11009 xmlXPathLastFunction);
11010 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
11011 xmlXPathLangFunction);
11012 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
11013 xmlXPathLocalNameFunction);
11014 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
11015 xmlXPathNotFunction);
11016 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
11017 xmlXPathNameFunction);
11018 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
11019 xmlXPathNamespaceURIFunction);
11020 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
11021 xmlXPathNormalizeFunction);
11022 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
11023 xmlXPathNumberFunction);
11024 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
11025 xmlXPathPositionFunction);
11026 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
11027 xmlXPathRoundFunction);
11028 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
11029 xmlXPathStringFunction);
11030 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
11031 xmlXPathStringLengthFunction);
11032 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
11033 xmlXPathStartsWithFunction);
11034 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
11035 xmlXPathSubstringFunction);
11036 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
11037 xmlXPathSubstringBeforeFunction);
11038 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
11039 xmlXPathSubstringAfterFunction);
11040 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
11041 xmlXPathSumFunction);
11042 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
11043 xmlXPathTrueFunction);
11044 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
11045 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000011046
11047 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
11048 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
11049 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000011050}
11051
11052#endif /* LIBXML_XPATH_ENABLED */