blob: 916b1037a64ffd1e4e79bd4209b78d7cd4a5e6cf [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 Veillard9adc0462003-03-24 18:39:54 +00003137 xmlNodePtr cur, tmp;
3138 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003139
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003140 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00003141 top = xmlNewDoc(NULL);
3142 top->name = (char *)
3143 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003144 ret->user = top;
3145 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003146 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003147 cur = val->nodesetval->nodeTab[0]->children;
3148 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003149 tmp = xmlDocCopyNode(cur, top, 1);
3150 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003151 cur = cur->next;
3152 }
3153 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003154 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003155 } else
Owen Taylor3473f882001-02-23 17:55:21 +00003156 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003157 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00003158 break;
3159 case XPATH_NODESET:
3160 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003161 /* Do not deallocate the copied tree value */
3162 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003163 break;
3164 case XPATH_LOCATIONSET:
3165#ifdef LIBXML_XPTR_ENABLED
3166 {
3167 xmlLocationSetPtr loc = val->user;
3168 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3169 break;
3170 }
3171#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00003172 case XPATH_USERS:
3173 ret->user = val->user;
3174 break;
3175 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00003176 xmlGenericError(xmlGenericErrorContext,
3177 "xmlXPathObjectCopy: unsupported type %d\n",
3178 val->type);
3179 break;
3180 }
3181 return(ret);
3182}
3183
3184/**
3185 * xmlXPathFreeObject:
3186 * @obj: the object to free
3187 *
3188 * Free up an xmlXPathObjectPtr object.
3189 */
3190void
3191xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3192 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003193 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00003194 if (obj->boolval) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003195 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003196 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00003197 xmlFreeNodeList((xmlNodePtr) obj->user);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003198 } else if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00003199 xmlXPathFreeValueTree(obj->nodesetval);
3200 } else {
3201 if (obj->nodesetval != NULL)
3202 xmlXPathFreeNodeSet(obj->nodesetval);
3203 }
Owen Taylor3473f882001-02-23 17:55:21 +00003204#ifdef LIBXML_XPTR_ENABLED
3205 } else if (obj->type == XPATH_LOCATIONSET) {
3206 if (obj->user != NULL)
3207 xmlXPtrFreeLocationSet(obj->user);
3208#endif
3209 } else if (obj->type == XPATH_STRING) {
3210 if (obj->stringval != NULL)
3211 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00003212 }
3213
Owen Taylor3473f882001-02-23 17:55:21 +00003214 xmlFree(obj);
3215}
3216
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003217
3218/************************************************************************
3219 * *
3220 * Type Casting Routines *
3221 * *
3222 ************************************************************************/
3223
3224/**
3225 * xmlXPathCastBooleanToString:
3226 * @val: a boolean
3227 *
3228 * Converts a boolean to its string value.
3229 *
3230 * Returns a newly allocated string.
3231 */
3232xmlChar *
3233xmlXPathCastBooleanToString (int val) {
3234 xmlChar *ret;
3235 if (val)
3236 ret = xmlStrdup((const xmlChar *) "true");
3237 else
3238 ret = xmlStrdup((const xmlChar *) "false");
3239 return(ret);
3240}
3241
3242/**
3243 * xmlXPathCastNumberToString:
3244 * @val: a number
3245 *
3246 * Converts a number to its string value.
3247 *
3248 * Returns a newly allocated string.
3249 */
3250xmlChar *
3251xmlXPathCastNumberToString (double val) {
3252 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00003253 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003254 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003255 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003256 break;
3257 case -1:
3258 ret = xmlStrdup((const xmlChar *) "-Infinity");
3259 break;
3260 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003261 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003262 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00003263 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
3264 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003265 } else {
3266 /* could be improved */
3267 char buf[100];
3268 xmlXPathFormatNumber(val, buf, 100);
3269 ret = xmlStrdup((const xmlChar *) buf);
3270 }
3271 }
3272 return(ret);
3273}
3274
3275/**
3276 * xmlXPathCastNodeToString:
3277 * @node: a node
3278 *
3279 * Converts a node to its string value.
3280 *
3281 * Returns a newly allocated string.
3282 */
3283xmlChar *
3284xmlXPathCastNodeToString (xmlNodePtr node) {
3285 return(xmlNodeGetContent(node));
3286}
3287
3288/**
3289 * xmlXPathCastNodeSetToString:
3290 * @ns: a node-set
3291 *
3292 * Converts a node-set to its string value.
3293 *
3294 * Returns a newly allocated string.
3295 */
3296xmlChar *
3297xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3298 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3299 return(xmlStrdup((const xmlChar *) ""));
3300
3301 xmlXPathNodeSetSort(ns);
3302 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3303}
3304
3305/**
3306 * xmlXPathCastToString:
3307 * @val: an XPath object
3308 *
3309 * Converts an existing object to its string() equivalent
3310 *
3311 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003312 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003313 * string object).
3314 */
3315xmlChar *
3316xmlXPathCastToString(xmlXPathObjectPtr val) {
3317 xmlChar *ret = NULL;
3318
3319 if (val == NULL)
3320 return(xmlStrdup((const xmlChar *) ""));
3321 switch (val->type) {
3322 case XPATH_UNDEFINED:
3323#ifdef DEBUG_EXPR
3324 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3325#endif
3326 ret = xmlStrdup((const xmlChar *) "");
3327 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003328 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003329 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003330 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3331 break;
3332 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00003333 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003334 case XPATH_BOOLEAN:
3335 ret = xmlXPathCastBooleanToString(val->boolval);
3336 break;
3337 case XPATH_NUMBER: {
3338 ret = xmlXPathCastNumberToString(val->floatval);
3339 break;
3340 }
3341 case XPATH_USERS:
3342 case XPATH_POINT:
3343 case XPATH_RANGE:
3344 case XPATH_LOCATIONSET:
3345 TODO
3346 ret = xmlStrdup((const xmlChar *) "");
3347 break;
3348 }
3349 return(ret);
3350}
3351
3352/**
3353 * xmlXPathConvertString:
3354 * @val: an XPath object
3355 *
3356 * Converts an existing object to its string() equivalent
3357 *
3358 * Returns the new object, the old one is freed (or the operation
3359 * is done directly on @val)
3360 */
3361xmlXPathObjectPtr
3362xmlXPathConvertString(xmlXPathObjectPtr val) {
3363 xmlChar *res = NULL;
3364
3365 if (val == NULL)
3366 return(xmlXPathNewCString(""));
3367
3368 switch (val->type) {
3369 case XPATH_UNDEFINED:
3370#ifdef DEBUG_EXPR
3371 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3372#endif
3373 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003374 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003375 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003376 res = xmlXPathCastNodeSetToString(val->nodesetval);
3377 break;
3378 case XPATH_STRING:
3379 return(val);
3380 case XPATH_BOOLEAN:
3381 res = xmlXPathCastBooleanToString(val->boolval);
3382 break;
3383 case XPATH_NUMBER:
3384 res = xmlXPathCastNumberToString(val->floatval);
3385 break;
3386 case XPATH_USERS:
3387 case XPATH_POINT:
3388 case XPATH_RANGE:
3389 case XPATH_LOCATIONSET:
3390 TODO;
3391 break;
3392 }
3393 xmlXPathFreeObject(val);
3394 if (res == NULL)
3395 return(xmlXPathNewCString(""));
3396 return(xmlXPathWrapString(res));
3397}
3398
3399/**
3400 * xmlXPathCastBooleanToNumber:
3401 * @val: a boolean
3402 *
3403 * Converts a boolean to its number value
3404 *
3405 * Returns the number value
3406 */
3407double
3408xmlXPathCastBooleanToNumber(int val) {
3409 if (val)
3410 return(1.0);
3411 return(0.0);
3412}
3413
3414/**
3415 * xmlXPathCastStringToNumber:
3416 * @val: a string
3417 *
3418 * Converts a string to its number value
3419 *
3420 * Returns the number value
3421 */
3422double
3423xmlXPathCastStringToNumber(const xmlChar * val) {
3424 return(xmlXPathStringEvalNumber(val));
3425}
3426
3427/**
3428 * xmlXPathCastNodeToNumber:
3429 * @node: a node
3430 *
3431 * Converts a node to its number value
3432 *
3433 * Returns the number value
3434 */
3435double
3436xmlXPathCastNodeToNumber (xmlNodePtr node) {
3437 xmlChar *strval;
3438 double ret;
3439
3440 if (node == NULL)
3441 return(xmlXPathNAN);
3442 strval = xmlXPathCastNodeToString(node);
3443 if (strval == NULL)
3444 return(xmlXPathNAN);
3445 ret = xmlXPathCastStringToNumber(strval);
3446 xmlFree(strval);
3447
3448 return(ret);
3449}
3450
3451/**
3452 * xmlXPathCastNodeSetToNumber:
3453 * @ns: a node-set
3454 *
3455 * Converts a node-set to its number value
3456 *
3457 * Returns the number value
3458 */
3459double
3460xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3461 xmlChar *str;
3462 double ret;
3463
3464 if (ns == NULL)
3465 return(xmlXPathNAN);
3466 str = xmlXPathCastNodeSetToString(ns);
3467 ret = xmlXPathCastStringToNumber(str);
3468 xmlFree(str);
3469 return(ret);
3470}
3471
3472/**
3473 * xmlXPathCastToNumber:
3474 * @val: an XPath object
3475 *
3476 * Converts an XPath object to its number value
3477 *
3478 * Returns the number value
3479 */
3480double
3481xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3482 double ret = 0.0;
3483
3484 if (val == NULL)
3485 return(xmlXPathNAN);
3486 switch (val->type) {
3487 case XPATH_UNDEFINED:
3488#ifdef DEGUB_EXPR
3489 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3490#endif
3491 ret = xmlXPathNAN;
3492 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003493 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003494 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003495 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3496 break;
3497 case XPATH_STRING:
3498 ret = xmlXPathCastStringToNumber(val->stringval);
3499 break;
3500 case XPATH_NUMBER:
3501 ret = val->floatval;
3502 break;
3503 case XPATH_BOOLEAN:
3504 ret = xmlXPathCastBooleanToNumber(val->boolval);
3505 break;
3506 case XPATH_USERS:
3507 case XPATH_POINT:
3508 case XPATH_RANGE:
3509 case XPATH_LOCATIONSET:
3510 TODO;
3511 ret = xmlXPathNAN;
3512 break;
3513 }
3514 return(ret);
3515}
3516
3517/**
3518 * xmlXPathConvertNumber:
3519 * @val: an XPath object
3520 *
3521 * Converts an existing object to its number() equivalent
3522 *
3523 * Returns the new object, the old one is freed (or the operation
3524 * is done directly on @val)
3525 */
3526xmlXPathObjectPtr
3527xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3528 xmlXPathObjectPtr ret;
3529
3530 if (val == NULL)
3531 return(xmlXPathNewFloat(0.0));
3532 if (val->type == XPATH_NUMBER)
3533 return(val);
3534 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3535 xmlXPathFreeObject(val);
3536 return(ret);
3537}
3538
3539/**
3540 * xmlXPathCastNumberToBoolean:
3541 * @val: a number
3542 *
3543 * Converts a number to its boolean value
3544 *
3545 * Returns the boolean value
3546 */
3547int
3548xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003549 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003550 return(0);
3551 return(1);
3552}
3553
3554/**
3555 * xmlXPathCastStringToBoolean:
3556 * @val: a string
3557 *
3558 * Converts a string to its boolean value
3559 *
3560 * Returns the boolean value
3561 */
3562int
3563xmlXPathCastStringToBoolean (const xmlChar *val) {
3564 if ((val == NULL) || (xmlStrlen(val) == 0))
3565 return(0);
3566 return(1);
3567}
3568
3569/**
3570 * xmlXPathCastNodeSetToBoolean:
3571 * @ns: a node-set
3572 *
3573 * Converts a node-set to its boolean value
3574 *
3575 * Returns the boolean value
3576 */
3577int
3578xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3579 if ((ns == NULL) || (ns->nodeNr == 0))
3580 return(0);
3581 return(1);
3582}
3583
3584/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003585 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003586 * @val: an XPath object
3587 *
3588 * Converts an XPath object to its boolean value
3589 *
3590 * Returns the boolean value
3591 */
3592int
3593xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3594 int ret = 0;
3595
3596 if (val == NULL)
3597 return(0);
3598 switch (val->type) {
3599 case XPATH_UNDEFINED:
3600#ifdef DEBUG_EXPR
3601 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3602#endif
3603 ret = 0;
3604 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003605 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003606 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003607 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3608 break;
3609 case XPATH_STRING:
3610 ret = xmlXPathCastStringToBoolean(val->stringval);
3611 break;
3612 case XPATH_NUMBER:
3613 ret = xmlXPathCastNumberToBoolean(val->floatval);
3614 break;
3615 case XPATH_BOOLEAN:
3616 ret = val->boolval;
3617 break;
3618 case XPATH_USERS:
3619 case XPATH_POINT:
3620 case XPATH_RANGE:
3621 case XPATH_LOCATIONSET:
3622 TODO;
3623 ret = 0;
3624 break;
3625 }
3626 return(ret);
3627}
3628
3629
3630/**
3631 * xmlXPathConvertBoolean:
3632 * @val: an XPath object
3633 *
3634 * Converts an existing object to its boolean() equivalent
3635 *
3636 * Returns the new object, the old one is freed (or the operation
3637 * is done directly on @val)
3638 */
3639xmlXPathObjectPtr
3640xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3641 xmlXPathObjectPtr ret;
3642
3643 if (val == NULL)
3644 return(xmlXPathNewBoolean(0));
3645 if (val->type == XPATH_BOOLEAN)
3646 return(val);
3647 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3648 xmlXPathFreeObject(val);
3649 return(ret);
3650}
3651
Owen Taylor3473f882001-02-23 17:55:21 +00003652/************************************************************************
3653 * *
3654 * Routines to handle XPath contexts *
3655 * *
3656 ************************************************************************/
3657
3658/**
3659 * xmlXPathNewContext:
3660 * @doc: the XML document
3661 *
3662 * Create a new xmlXPathContext
3663 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00003664 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00003665 */
3666xmlXPathContextPtr
3667xmlXPathNewContext(xmlDocPtr doc) {
3668 xmlXPathContextPtr ret;
3669
3670 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3671 if (ret == NULL) {
3672 xmlGenericError(xmlGenericErrorContext,
3673 "xmlXPathNewContext: out of memory\n");
3674 return(NULL);
3675 }
3676 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3677 ret->doc = doc;
3678 ret->node = NULL;
3679
3680 ret->varHash = NULL;
3681
3682 ret->nb_types = 0;
3683 ret->max_types = 0;
3684 ret->types = NULL;
3685
3686 ret->funcHash = xmlHashCreate(0);
3687
3688 ret->nb_axis = 0;
3689 ret->max_axis = 0;
3690 ret->axis = NULL;
3691
3692 ret->nsHash = NULL;
3693 ret->user = NULL;
3694
3695 ret->contextSize = -1;
3696 ret->proximityPosition = -1;
3697
3698 xmlXPathRegisterAllFunctions(ret);
3699
3700 return(ret);
3701}
3702
3703/**
3704 * xmlXPathFreeContext:
3705 * @ctxt: the context to free
3706 *
3707 * Free up an xmlXPathContext
3708 */
3709void
3710xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3711 xmlXPathRegisteredNsCleanup(ctxt);
3712 xmlXPathRegisteredFuncsCleanup(ctxt);
3713 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003714 xmlFree(ctxt);
3715}
3716
3717/************************************************************************
3718 * *
3719 * Routines to handle XPath parser contexts *
3720 * *
3721 ************************************************************************/
3722
3723#define CHECK_CTXT(ctxt) \
3724 if (ctxt == NULL) { \
3725 xmlGenericError(xmlGenericErrorContext, \
3726 "%s:%d Internal error: ctxt == NULL\n", \
3727 __FILE__, __LINE__); \
3728 } \
3729
3730
3731#define CHECK_CONTEXT(ctxt) \
3732 if (ctxt == NULL) { \
3733 xmlGenericError(xmlGenericErrorContext, \
3734 "%s:%d Internal error: no context\n", \
3735 __FILE__, __LINE__); \
3736 } \
3737 else if (ctxt->doc == NULL) { \
3738 xmlGenericError(xmlGenericErrorContext, \
3739 "%s:%d Internal error: no document\n", \
3740 __FILE__, __LINE__); \
3741 } \
3742 else if (ctxt->doc->children == NULL) { \
3743 xmlGenericError(xmlGenericErrorContext, \
3744 "%s:%d Internal error: document without root\n", \
3745 __FILE__, __LINE__); \
3746 } \
3747
3748
3749/**
3750 * xmlXPathNewParserContext:
3751 * @str: the XPath expression
3752 * @ctxt: the XPath context
3753 *
3754 * Create a new xmlXPathParserContext
3755 *
3756 * Returns the xmlXPathParserContext just allocated.
3757 */
3758xmlXPathParserContextPtr
3759xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3760 xmlXPathParserContextPtr ret;
3761
3762 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3763 if (ret == NULL) {
3764 xmlGenericError(xmlGenericErrorContext,
3765 "xmlXPathNewParserContext: out of memory\n");
3766 return(NULL);
3767 }
3768 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3769 ret->cur = ret->base = str;
3770 ret->context = ctxt;
3771
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003772 ret->comp = xmlXPathNewCompExpr();
3773 if (ret->comp == NULL) {
3774 xmlFree(ret->valueTab);
3775 xmlFree(ret);
3776 return(NULL);
3777 }
3778
3779 return(ret);
3780}
3781
3782/**
3783 * xmlXPathCompParserContext:
3784 * @comp: the XPath compiled expression
3785 * @ctxt: the XPath context
3786 *
3787 * Create a new xmlXPathParserContext when processing a compiled expression
3788 *
3789 * Returns the xmlXPathParserContext just allocated.
3790 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003791static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003792xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3793 xmlXPathParserContextPtr ret;
3794
3795 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3796 if (ret == NULL) {
3797 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003798 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003799 return(NULL);
3800 }
3801 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3802
Owen Taylor3473f882001-02-23 17:55:21 +00003803 /* Allocate the value stack */
3804 ret->valueTab = (xmlXPathObjectPtr *)
3805 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003806 if (ret->valueTab == NULL) {
3807 xmlFree(ret);
3808 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003809 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003810 return(NULL);
3811 }
Owen Taylor3473f882001-02-23 17:55:21 +00003812 ret->valueNr = 0;
3813 ret->valueMax = 10;
3814 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003815
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00003816 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003817 ret->comp = comp;
3818
Owen Taylor3473f882001-02-23 17:55:21 +00003819 return(ret);
3820}
3821
3822/**
3823 * xmlXPathFreeParserContext:
3824 * @ctxt: the context to free
3825 *
3826 * Free up an xmlXPathParserContext
3827 */
3828void
3829xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
3830 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003831 xmlFree(ctxt->valueTab);
3832 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003833 if (ctxt->comp)
3834 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00003835 xmlFree(ctxt);
3836}
3837
3838/************************************************************************
3839 * *
3840 * The implicit core function library *
3841 * *
3842 ************************************************************************/
3843
Owen Taylor3473f882001-02-23 17:55:21 +00003844/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00003845 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00003846 * @node: a node pointer
3847 *
3848 * Function computing the beginning of the string value of the node,
3849 * used to speed up comparisons
3850 *
3851 * Returns an int usable as a hash
3852 */
3853static unsigned int
3854xmlXPathNodeValHash(xmlNodePtr node) {
3855 int len = 2;
3856 const xmlChar * string = NULL;
3857 xmlNodePtr tmp = NULL;
3858 unsigned int ret = 0;
3859
3860 if (node == NULL)
3861 return(0);
3862
Daniel Veillard9adc0462003-03-24 18:39:54 +00003863 if (node->type == XML_DOCUMENT_NODE) {
3864 tmp = xmlDocGetRootElement((xmlDocPtr) node);
3865 if (tmp == NULL)
3866 node = node->children;
3867 else
3868 node = tmp;
3869
3870 if (node == NULL)
3871 return(0);
3872 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003873
3874 switch (node->type) {
3875 case XML_COMMENT_NODE:
3876 case XML_PI_NODE:
3877 case XML_CDATA_SECTION_NODE:
3878 case XML_TEXT_NODE:
3879 string = node->content;
3880 if (string == NULL)
3881 return(0);
3882 if (string[0] == 0)
3883 return(0);
3884 return(((unsigned int) string[0]) +
3885 (((unsigned int) string[1]) << 8));
3886 case XML_NAMESPACE_DECL:
3887 string = ((xmlNsPtr)node)->href;
3888 if (string == NULL)
3889 return(0);
3890 if (string[0] == 0)
3891 return(0);
3892 return(((unsigned int) string[0]) +
3893 (((unsigned int) string[1]) << 8));
3894 case XML_ATTRIBUTE_NODE:
3895 tmp = ((xmlAttrPtr) node)->children;
3896 break;
3897 case XML_ELEMENT_NODE:
3898 tmp = node->children;
3899 break;
3900 default:
3901 return(0);
3902 }
3903 while (tmp != NULL) {
3904 switch (tmp->type) {
3905 case XML_COMMENT_NODE:
3906 case XML_PI_NODE:
3907 case XML_CDATA_SECTION_NODE:
3908 case XML_TEXT_NODE:
3909 string = tmp->content;
3910 break;
3911 case XML_NAMESPACE_DECL:
3912 string = ((xmlNsPtr)tmp)->href;
3913 break;
3914 default:
3915 break;
3916 }
3917 if ((string != NULL) && (string[0] != 0)) {
3918 if (string[0] == 0)
3919 return(0);
3920 if (len == 1) {
3921 return(ret + (((unsigned int) string[0]) << 8));
3922 }
3923 if (string[1] == 0) {
3924 len = 1;
3925 ret = (unsigned int) string[0];
3926 } else {
3927 return(((unsigned int) string[0]) +
3928 (((unsigned int) string[1]) << 8));
3929 }
3930 }
3931 /*
3932 * Skip to next node
3933 */
3934 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
3935 if (tmp->children->type != XML_ENTITY_DECL) {
3936 tmp = tmp->children;
3937 continue;
3938 }
3939 }
3940 if (tmp == node)
3941 break;
3942
3943 if (tmp->next != NULL) {
3944 tmp = tmp->next;
3945 continue;
3946 }
3947
3948 do {
3949 tmp = tmp->parent;
3950 if (tmp == NULL)
3951 break;
3952 if (tmp == node) {
3953 tmp = NULL;
3954 break;
3955 }
3956 if (tmp->next != NULL) {
3957 tmp = tmp->next;
3958 break;
3959 }
3960 } while (tmp != NULL);
3961 }
3962 return(ret);
3963}
3964
3965/**
3966 * xmlXPathStringHash:
3967 * @string: a string
3968 *
3969 * Function computing the beginning of the string value of the node,
3970 * used to speed up comparisons
3971 *
3972 * Returns an int usable as a hash
3973 */
3974static unsigned int
3975xmlXPathStringHash(const xmlChar * string) {
3976 if (string == NULL)
3977 return((unsigned int) 0);
3978 if (string[0] == 0)
3979 return(0);
3980 return(((unsigned int) string[0]) +
3981 (((unsigned int) string[1]) << 8));
3982}
3983
3984/**
Owen Taylor3473f882001-02-23 17:55:21 +00003985 * xmlXPathCompareNodeSetFloat:
3986 * @ctxt: the XPath Parser context
3987 * @inf: less than (1) or greater than (0)
3988 * @strict: is the comparison strict
3989 * @arg: the node set
3990 * @f: the value
3991 *
3992 * Implement the compare operation between a nodeset and a number
3993 * @ns < @val (1, 1, ...
3994 * @ns <= @val (1, 0, ...
3995 * @ns > @val (0, 1, ...
3996 * @ns >= @val (0, 0, ...
3997 *
3998 * If one object to be compared is a node-set and the other is a number,
3999 * then the comparison will be true if and only if there is a node in the
4000 * node-set such that the result of performing the comparison on the number
4001 * to be compared and on the result of converting the string-value of that
4002 * node to a number using the number function is true.
4003 *
4004 * Returns 0 or 1 depending on the results of the test.
4005 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004006static int
Owen Taylor3473f882001-02-23 17:55:21 +00004007xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
4008 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
4009 int i, ret = 0;
4010 xmlNodeSetPtr ns;
4011 xmlChar *str2;
4012
4013 if ((f == NULL) || (arg == NULL) ||
4014 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4015 xmlXPathFreeObject(arg);
4016 xmlXPathFreeObject(f);
4017 return(0);
4018 }
4019 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004020 if (ns != NULL) {
4021 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004022 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004023 if (str2 != NULL) {
4024 valuePush(ctxt,
4025 xmlXPathNewString(str2));
4026 xmlFree(str2);
4027 xmlXPathNumberFunction(ctxt, 1);
4028 valuePush(ctxt, xmlXPathObjectCopy(f));
4029 ret = xmlXPathCompareValues(ctxt, inf, strict);
4030 if (ret)
4031 break;
4032 }
4033 }
Owen Taylor3473f882001-02-23 17:55:21 +00004034 }
4035 xmlXPathFreeObject(arg);
4036 xmlXPathFreeObject(f);
4037 return(ret);
4038}
4039
4040/**
4041 * xmlXPathCompareNodeSetString:
4042 * @ctxt: the XPath Parser context
4043 * @inf: less than (1) or greater than (0)
4044 * @strict: is the comparison strict
4045 * @arg: the node set
4046 * @s: the value
4047 *
4048 * Implement the compare operation between a nodeset and a string
4049 * @ns < @val (1, 1, ...
4050 * @ns <= @val (1, 0, ...
4051 * @ns > @val (0, 1, ...
4052 * @ns >= @val (0, 0, ...
4053 *
4054 * If one object to be compared is a node-set and the other is a string,
4055 * then the comparison will be true if and only if there is a node in
4056 * the node-set such that the result of performing the comparison on the
4057 * string-value of the node and the other string is true.
4058 *
4059 * Returns 0 or 1 depending on the results of the test.
4060 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004061static int
Owen Taylor3473f882001-02-23 17:55:21 +00004062xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
4063 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
4064 int i, ret = 0;
4065 xmlNodeSetPtr ns;
4066 xmlChar *str2;
4067
4068 if ((s == NULL) || (arg == NULL) ||
4069 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4070 xmlXPathFreeObject(arg);
4071 xmlXPathFreeObject(s);
4072 return(0);
4073 }
4074 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004075 if (ns != NULL) {
4076 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004077 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004078 if (str2 != NULL) {
4079 valuePush(ctxt,
4080 xmlXPathNewString(str2));
4081 xmlFree(str2);
4082 valuePush(ctxt, xmlXPathObjectCopy(s));
4083 ret = xmlXPathCompareValues(ctxt, inf, strict);
4084 if (ret)
4085 break;
4086 }
4087 }
Owen Taylor3473f882001-02-23 17:55:21 +00004088 }
4089 xmlXPathFreeObject(arg);
4090 xmlXPathFreeObject(s);
4091 return(ret);
4092}
4093
4094/**
4095 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004096 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00004097 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004098 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00004099 * @arg2: the second node set object
4100 *
4101 * Implement the compare operation on nodesets:
4102 *
4103 * If both objects to be compared are node-sets, then the comparison
4104 * will be true if and only if there is a node in the first node-set
4105 * and a node in the second node-set such that the result of performing
4106 * the comparison on the string-values of the two nodes is true.
4107 * ....
4108 * When neither object to be compared is a node-set and the operator
4109 * is <=, <, >= or >, then the objects are compared by converting both
4110 * objects to numbers and comparing the numbers according to IEEE 754.
4111 * ....
4112 * The number function converts its argument to a number as follows:
4113 * - a string that consists of optional whitespace followed by an
4114 * optional minus sign followed by a Number followed by whitespace
4115 * is converted to the IEEE 754 number that is nearest (according
4116 * to the IEEE 754 round-to-nearest rule) to the mathematical value
4117 * represented by the string; any other string is converted to NaN
4118 *
4119 * Conclusion all nodes need to be converted first to their string value
4120 * and then the comparison must be done when possible
4121 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004122static int
4123xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00004124 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4125 int i, j, init = 0;
4126 double val1;
4127 double *values2;
4128 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004129 xmlNodeSetPtr ns1;
4130 xmlNodeSetPtr ns2;
4131
4132 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004133 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4134 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004135 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004136 }
Owen Taylor3473f882001-02-23 17:55:21 +00004137 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004138 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4139 xmlXPathFreeObject(arg1);
4140 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004141 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004142 }
Owen Taylor3473f882001-02-23 17:55:21 +00004143
4144 ns1 = arg1->nodesetval;
4145 ns2 = arg2->nodesetval;
4146
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004147 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004148 xmlXPathFreeObject(arg1);
4149 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004150 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004151 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004152 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004153 xmlXPathFreeObject(arg1);
4154 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004155 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004156 }
Owen Taylor3473f882001-02-23 17:55:21 +00004157
4158 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4159 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004160 xmlXPathFreeObject(arg1);
4161 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004162 return(0);
4163 }
4164 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004165 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004166 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004167 continue;
4168 for (j = 0;j < ns2->nodeNr;j++) {
4169 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004170 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004171 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004172 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004173 continue;
4174 if (inf && strict)
4175 ret = (val1 < values2[j]);
4176 else if (inf && !strict)
4177 ret = (val1 <= values2[j]);
4178 else if (!inf && strict)
4179 ret = (val1 > values2[j]);
4180 else if (!inf && !strict)
4181 ret = (val1 >= values2[j]);
4182 if (ret)
4183 break;
4184 }
4185 if (ret)
4186 break;
4187 init = 1;
4188 }
4189 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004190 xmlXPathFreeObject(arg1);
4191 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004192 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004193}
4194
4195/**
4196 * xmlXPathCompareNodeSetValue:
4197 * @ctxt: the XPath Parser context
4198 * @inf: less than (1) or greater than (0)
4199 * @strict: is the comparison strict
4200 * @arg: the node set
4201 * @val: the value
4202 *
4203 * Implement the compare operation between a nodeset and a value
4204 * @ns < @val (1, 1, ...
4205 * @ns <= @val (1, 0, ...
4206 * @ns > @val (0, 1, ...
4207 * @ns >= @val (0, 0, ...
4208 *
4209 * If one object to be compared is a node-set and the other is a boolean,
4210 * then the comparison will be true if and only if the result of performing
4211 * the comparison on the boolean and on the result of converting
4212 * the node-set to a boolean using the boolean function is true.
4213 *
4214 * Returns 0 or 1 depending on the results of the test.
4215 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004216static int
Owen Taylor3473f882001-02-23 17:55:21 +00004217xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4218 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4219 if ((val == NULL) || (arg == NULL) ||
4220 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4221 return(0);
4222
4223 switch(val->type) {
4224 case XPATH_NUMBER:
4225 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4226 case XPATH_NODESET:
4227 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004228 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004229 case XPATH_STRING:
4230 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4231 case XPATH_BOOLEAN:
4232 valuePush(ctxt, arg);
4233 xmlXPathBooleanFunction(ctxt, 1);
4234 valuePush(ctxt, val);
4235 return(xmlXPathCompareValues(ctxt, inf, strict));
4236 default:
4237 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004238 }
4239 return(0);
4240}
4241
4242/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004243 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00004244 * @arg: the nodeset object argument
4245 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00004246 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004247 *
4248 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4249 * If one object to be compared is a node-set and the other is a string,
4250 * then the comparison will be true if and only if there is a node in
4251 * the node-set such that the result of performing the comparison on the
4252 * string-value of the node and the other string is true.
4253 *
4254 * Returns 0 or 1 depending on the results of the test.
4255 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004256static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004257xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004258{
Owen Taylor3473f882001-02-23 17:55:21 +00004259 int i;
4260 xmlNodeSetPtr ns;
4261 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004262 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004263
4264 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004265 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4266 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004267 ns = arg->nodesetval;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004268 hash = xmlXPathStringHash(str);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004269 if (ns == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004270 return (0);
Daniel Veillard73c9c042001-07-05 20:02:54 +00004271 if (ns->nodeNr <= 0) {
4272 if (hash == 0)
William M. Brack0c022ad2002-07-12 00:56:01 +00004273 return(neq ^ 1);
4274 return(neq);
Daniel Veillard73c9c042001-07-05 20:02:54 +00004275 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004276 for (i = 0; i < ns->nodeNr; i++) {
4277 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4278 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4279 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4280 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004281 if (neq)
4282 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004283 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00004284 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
4285 if (neq)
4286 continue;
4287 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00004288 } else if (neq) {
4289 if (str2 != NULL)
4290 xmlFree(str2);
4291 return (1);
4292 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004293 if (str2 != NULL)
4294 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004295 } else if (neq)
4296 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00004297 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004298 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004299}
4300
4301/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004302 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00004303 * @arg: the nodeset object argument
4304 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00004305 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004306 *
4307 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4308 * If one object to be compared is a node-set and the other is a number,
4309 * then the comparison will be true if and only if there is a node in
4310 * the node-set such that the result of performing the comparison on the
4311 * number to be compared and on the result of converting the string-value
4312 * of that node to a number using the number function is true.
4313 *
4314 * Returns 0 or 1 depending on the results of the test.
4315 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004316static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004317xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
4318 xmlXPathObjectPtr arg, double f, int neq) {
4319 int i, ret=0;
4320 xmlNodeSetPtr ns;
4321 xmlChar *str2;
4322 xmlXPathObjectPtr val;
4323 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00004324
4325 if ((arg == NULL) ||
4326 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4327 return(0);
4328
William M. Brack0c022ad2002-07-12 00:56:01 +00004329 ns = arg->nodesetval;
4330 if (ns != NULL) {
4331 for (i=0;i<ns->nodeNr;i++) {
4332 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4333 if (str2 != NULL) {
4334 valuePush(ctxt, xmlXPathNewString(str2));
4335 xmlFree(str2);
4336 xmlXPathNumberFunction(ctxt, 1);
4337 val = valuePop(ctxt);
4338 v = val->floatval;
4339 xmlXPathFreeObject(val);
4340 if (!xmlXPathIsNaN(v)) {
4341 if ((!neq) && (v==f)) {
4342 ret = 1;
4343 break;
4344 } else if ((neq) && (v!=f)) {
4345 ret = 1;
4346 break;
4347 }
4348 }
4349 }
4350 }
4351 }
4352
4353 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004354}
4355
4356
4357/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004358 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00004359 * @arg1: first nodeset object argument
4360 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00004361 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004362 *
William M. Brack0c022ad2002-07-12 00:56:01 +00004363 * Implement the equal / not equal operation on XPath nodesets:
4364 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00004365 * If both objects to be compared are node-sets, then the comparison
4366 * will be true if and only if there is a node in the first node-set and
4367 * a node in the second node-set such that the result of performing the
4368 * comparison on the string-values of the two nodes is true.
4369 *
4370 * (needless to say, this is a costly operation)
4371 *
4372 * Returns 0 or 1 depending on the results of the test.
4373 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004374static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004375xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00004376 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004377 unsigned int *hashs1;
4378 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004379 xmlChar **values1;
4380 xmlChar **values2;
4381 int ret = 0;
4382 xmlNodeSetPtr ns1;
4383 xmlNodeSetPtr ns2;
4384
4385 if ((arg1 == NULL) ||
4386 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4387 return(0);
4388 if ((arg2 == NULL) ||
4389 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4390 return(0);
4391
4392 ns1 = arg1->nodesetval;
4393 ns2 = arg2->nodesetval;
4394
Daniel Veillard911f49a2001-04-07 15:39:35 +00004395 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004396 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004397 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004398 return(0);
4399
4400 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00004401 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00004402 */
William M. Brack0c022ad2002-07-12 00:56:01 +00004403 if (neq == 0)
4404 for (i = 0;i < ns1->nodeNr;i++)
4405 for (j = 0;j < ns2->nodeNr;j++)
4406 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4407 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00004408
4409 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
4410 if (values1 == NULL)
4411 return(0);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004412 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4413 if (hashs1 == NULL) {
4414 xmlFree(values1);
4415 return(0);
4416 }
Owen Taylor3473f882001-02-23 17:55:21 +00004417 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4418 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4419 if (values2 == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004420 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004421 xmlFree(values1);
4422 return(0);
4423 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004424 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4425 if (hashs2 == NULL) {
4426 xmlFree(hashs1);
4427 xmlFree(values1);
4428 xmlFree(values2);
4429 return(0);
4430 }
Owen Taylor3473f882001-02-23 17:55:21 +00004431 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4432 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004433 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004434 for (j = 0;j < ns2->nodeNr;j++) {
4435 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004436 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004437 if (hashs1[i] != hashs2[j]) {
4438 if (neq) {
4439 ret = 1;
4440 break;
4441 }
4442 }
4443 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004444 if (values1[i] == NULL)
4445 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4446 if (values2[j] == NULL)
4447 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004448 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004449 if (ret)
4450 break;
4451 }
Owen Taylor3473f882001-02-23 17:55:21 +00004452 }
4453 if (ret)
4454 break;
4455 }
4456 for (i = 0;i < ns1->nodeNr;i++)
4457 if (values1[i] != NULL)
4458 xmlFree(values1[i]);
4459 for (j = 0;j < ns2->nodeNr;j++)
4460 if (values2[j] != NULL)
4461 xmlFree(values2[j]);
4462 xmlFree(values1);
4463 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004464 xmlFree(hashs1);
4465 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004466 return(ret);
4467}
4468
William M. Brack0c022ad2002-07-12 00:56:01 +00004469static int
4470xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
4471 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00004472 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00004473 /*
4474 *At this point we are assured neither arg1 nor arg2
4475 *is a nodeset, so we can just pick the appropriate routine.
4476 */
Owen Taylor3473f882001-02-23 17:55:21 +00004477 switch (arg1->type) {
4478 case XPATH_UNDEFINED:
4479#ifdef DEBUG_EXPR
4480 xmlGenericError(xmlGenericErrorContext,
4481 "Equal: undefined\n");
4482#endif
4483 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004484 case XPATH_BOOLEAN:
4485 switch (arg2->type) {
4486 case XPATH_UNDEFINED:
4487#ifdef DEBUG_EXPR
4488 xmlGenericError(xmlGenericErrorContext,
4489 "Equal: undefined\n");
4490#endif
4491 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004492 case XPATH_BOOLEAN:
4493#ifdef DEBUG_EXPR
4494 xmlGenericError(xmlGenericErrorContext,
4495 "Equal: %d boolean %d \n",
4496 arg1->boolval, arg2->boolval);
4497#endif
4498 ret = (arg1->boolval == arg2->boolval);
4499 break;
4500 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00004501 ret = (arg1->boolval ==
4502 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004503 break;
4504 case XPATH_STRING:
4505 if ((arg2->stringval == NULL) ||
4506 (arg2->stringval[0] == 0)) ret = 0;
4507 else
4508 ret = 1;
4509 ret = (arg1->boolval == ret);
4510 break;
4511 case XPATH_USERS:
4512 case XPATH_POINT:
4513 case XPATH_RANGE:
4514 case XPATH_LOCATIONSET:
4515 TODO
4516 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004517 case XPATH_NODESET:
4518 case XPATH_XSLT_TREE:
4519 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004520 }
4521 break;
4522 case XPATH_NUMBER:
4523 switch (arg2->type) {
4524 case XPATH_UNDEFINED:
4525#ifdef DEBUG_EXPR
4526 xmlGenericError(xmlGenericErrorContext,
4527 "Equal: undefined\n");
4528#endif
4529 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004530 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00004531 ret = (arg2->boolval==
4532 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004533 break;
4534 case XPATH_STRING:
4535 valuePush(ctxt, arg2);
4536 xmlXPathNumberFunction(ctxt, 1);
4537 arg2 = valuePop(ctxt);
4538 /* no break on purpose */
4539 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004540 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004541 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4542 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004543 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4544 if (xmlXPathIsInf(arg2->floatval) == 1)
4545 ret = 1;
4546 else
4547 ret = 0;
4548 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4549 if (xmlXPathIsInf(arg2->floatval) == -1)
4550 ret = 1;
4551 else
4552 ret = 0;
4553 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4554 if (xmlXPathIsInf(arg1->floatval) == 1)
4555 ret = 1;
4556 else
4557 ret = 0;
4558 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4559 if (xmlXPathIsInf(arg1->floatval) == -1)
4560 ret = 1;
4561 else
4562 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004563 } else {
4564 ret = (arg1->floatval == arg2->floatval);
4565 }
Owen Taylor3473f882001-02-23 17:55:21 +00004566 break;
4567 case XPATH_USERS:
4568 case XPATH_POINT:
4569 case XPATH_RANGE:
4570 case XPATH_LOCATIONSET:
4571 TODO
4572 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004573 case XPATH_NODESET:
4574 case XPATH_XSLT_TREE:
4575 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004576 }
4577 break;
4578 case XPATH_STRING:
4579 switch (arg2->type) {
4580 case XPATH_UNDEFINED:
4581#ifdef DEBUG_EXPR
4582 xmlGenericError(xmlGenericErrorContext,
4583 "Equal: undefined\n");
4584#endif
4585 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004586 case XPATH_BOOLEAN:
4587 if ((arg1->stringval == NULL) ||
4588 (arg1->stringval[0] == 0)) ret = 0;
4589 else
4590 ret = 1;
4591 ret = (arg2->boolval == ret);
4592 break;
4593 case XPATH_STRING:
4594 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4595 break;
4596 case XPATH_NUMBER:
4597 valuePush(ctxt, arg1);
4598 xmlXPathNumberFunction(ctxt, 1);
4599 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004600 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004601 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4602 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004603 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4604 if (xmlXPathIsInf(arg2->floatval) == 1)
4605 ret = 1;
4606 else
4607 ret = 0;
4608 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4609 if (xmlXPathIsInf(arg2->floatval) == -1)
4610 ret = 1;
4611 else
4612 ret = 0;
4613 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4614 if (xmlXPathIsInf(arg1->floatval) == 1)
4615 ret = 1;
4616 else
4617 ret = 0;
4618 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4619 if (xmlXPathIsInf(arg1->floatval) == -1)
4620 ret = 1;
4621 else
4622 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004623 } else {
4624 ret = (arg1->floatval == arg2->floatval);
4625 }
Owen Taylor3473f882001-02-23 17:55:21 +00004626 break;
4627 case XPATH_USERS:
4628 case XPATH_POINT:
4629 case XPATH_RANGE:
4630 case XPATH_LOCATIONSET:
4631 TODO
4632 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004633 case XPATH_NODESET:
4634 case XPATH_XSLT_TREE:
4635 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004636 }
4637 break;
4638 case XPATH_USERS:
4639 case XPATH_POINT:
4640 case XPATH_RANGE:
4641 case XPATH_LOCATIONSET:
4642 TODO
4643 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004644 case XPATH_NODESET:
4645 case XPATH_XSLT_TREE:
4646 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004647 }
4648 xmlXPathFreeObject(arg1);
4649 xmlXPathFreeObject(arg2);
4650 return(ret);
4651}
4652
William M. Brack0c022ad2002-07-12 00:56:01 +00004653/**
4654 * xmlXPathEqualValues:
4655 * @ctxt: the XPath Parser context
4656 *
4657 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4658 *
4659 * Returns 0 or 1 depending on the results of the test.
4660 */
4661int
4662xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4663 xmlXPathObjectPtr arg1, arg2, argtmp;
4664 int ret = 0;
4665
4666 arg2 = valuePop(ctxt);
4667 arg1 = valuePop(ctxt);
4668 if ((arg1 == NULL) || (arg2 == NULL)) {
4669 if (arg1 != NULL)
4670 xmlXPathFreeObject(arg1);
4671 else
4672 xmlXPathFreeObject(arg2);
4673 XP_ERROR0(XPATH_INVALID_OPERAND);
4674 }
4675
4676 if (arg1 == arg2) {
4677#ifdef DEBUG_EXPR
4678 xmlGenericError(xmlGenericErrorContext,
4679 "Equal: by pointer\n");
4680#endif
4681 return(1);
4682 }
4683
4684 /*
4685 *If either argument is a nodeset, it's a 'special case'
4686 */
4687 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4688 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4689 /*
4690 *Hack it to assure arg1 is the nodeset
4691 */
4692 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4693 argtmp = arg2;
4694 arg2 = arg1;
4695 arg1 = argtmp;
4696 }
4697 switch (arg2->type) {
4698 case XPATH_UNDEFINED:
4699#ifdef DEBUG_EXPR
4700 xmlGenericError(xmlGenericErrorContext,
4701 "Equal: undefined\n");
4702#endif
4703 break;
4704 case XPATH_NODESET:
4705 case XPATH_XSLT_TREE:
4706 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
4707 break;
4708 case XPATH_BOOLEAN:
4709 if ((arg1->nodesetval == NULL) ||
4710 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4711 else
4712 ret = 1;
4713 ret = (ret == arg2->boolval);
4714 break;
4715 case XPATH_NUMBER:
4716 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
4717 break;
4718 case XPATH_STRING:
4719 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
4720 break;
4721 case XPATH_USERS:
4722 case XPATH_POINT:
4723 case XPATH_RANGE:
4724 case XPATH_LOCATIONSET:
4725 TODO
4726 break;
4727 }
4728 xmlXPathFreeObject(arg1);
4729 xmlXPathFreeObject(arg2);
4730 return(ret);
4731 }
4732
4733 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4734}
4735
4736/**
4737 * xmlXPathNotEqualValues:
4738 * @ctxt: the XPath Parser context
4739 *
4740 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4741 *
4742 * Returns 0 or 1 depending on the results of the test.
4743 */
4744int
4745xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
4746 xmlXPathObjectPtr arg1, arg2, argtmp;
4747 int ret = 0;
4748
4749 arg2 = valuePop(ctxt);
4750 arg1 = valuePop(ctxt);
4751 if ((arg1 == NULL) || (arg2 == NULL)) {
4752 if (arg1 != NULL)
4753 xmlXPathFreeObject(arg1);
4754 else
4755 xmlXPathFreeObject(arg2);
4756 XP_ERROR0(XPATH_INVALID_OPERAND);
4757 }
4758
4759 if (arg1 == arg2) {
4760#ifdef DEBUG_EXPR
4761 xmlGenericError(xmlGenericErrorContext,
4762 "NotEqual: by pointer\n");
4763#endif
4764 return(0);
4765 }
4766
4767 /*
4768 *If either argument is a nodeset, it's a 'special case'
4769 */
4770 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4771 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4772 /*
4773 *Hack it to assure arg1 is the nodeset
4774 */
4775 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4776 argtmp = arg2;
4777 arg2 = arg1;
4778 arg1 = argtmp;
4779 }
4780 switch (arg2->type) {
4781 case XPATH_UNDEFINED:
4782#ifdef DEBUG_EXPR
4783 xmlGenericError(xmlGenericErrorContext,
4784 "NotEqual: undefined\n");
4785#endif
4786 break;
4787 case XPATH_NODESET:
4788 case XPATH_XSLT_TREE:
4789 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
4790 break;
4791 case XPATH_BOOLEAN:
4792 if ((arg1->nodesetval == NULL) ||
4793 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4794 else
4795 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00004796 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00004797 break;
4798 case XPATH_NUMBER:
4799 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
4800 break;
4801 case XPATH_STRING:
4802 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
4803 break;
4804 case XPATH_USERS:
4805 case XPATH_POINT:
4806 case XPATH_RANGE:
4807 case XPATH_LOCATIONSET:
4808 TODO
4809 break;
4810 }
4811 xmlXPathFreeObject(arg1);
4812 xmlXPathFreeObject(arg2);
4813 return(ret);
4814 }
4815
4816 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4817}
Owen Taylor3473f882001-02-23 17:55:21 +00004818
4819/**
4820 * xmlXPathCompareValues:
4821 * @ctxt: the XPath Parser context
4822 * @inf: less than (1) or greater than (0)
4823 * @strict: is the comparison strict
4824 *
4825 * Implement the compare operation on XPath objects:
4826 * @arg1 < @arg2 (1, 1, ...
4827 * @arg1 <= @arg2 (1, 0, ...
4828 * @arg1 > @arg2 (0, 1, ...
4829 * @arg1 >= @arg2 (0, 0, ...
4830 *
4831 * When neither object to be compared is a node-set and the operator is
4832 * <=, <, >=, >, then the objects are compared by converted both objects
4833 * to numbers and comparing the numbers according to IEEE 754. The <
4834 * comparison will be true if and only if the first number is less than the
4835 * second number. The <= comparison will be true if and only if the first
4836 * number is less than or equal to the second number. The > comparison
4837 * will be true if and only if the first number is greater than the second
4838 * number. The >= comparison will be true if and only if the first number
4839 * is greater than or equal to the second number.
4840 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004841 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00004842 */
4843int
4844xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004845 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004846 xmlXPathObjectPtr arg1, arg2;
4847
William M. Brack0c022ad2002-07-12 00:56:01 +00004848 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00004849 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00004850 if ((arg1 == NULL) || (arg2 == NULL)) {
4851 if (arg1 != NULL)
4852 xmlXPathFreeObject(arg1);
4853 else
4854 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004855 XP_ERROR0(XPATH_INVALID_OPERAND);
4856 }
4857
William M. Brack0c022ad2002-07-12 00:56:01 +00004858 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4859 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4860 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
4861 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004862 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004863 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00004864 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004865 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
4866 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004867 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004868 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
4869 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00004870 }
4871 }
4872 return(ret);
4873 }
4874
4875 if (arg1->type != XPATH_NUMBER) {
4876 valuePush(ctxt, arg1);
4877 xmlXPathNumberFunction(ctxt, 1);
4878 arg1 = valuePop(ctxt);
4879 }
4880 if (arg1->type != XPATH_NUMBER) {
4881 xmlXPathFreeObject(arg1);
4882 xmlXPathFreeObject(arg2);
4883 XP_ERROR0(XPATH_INVALID_OPERAND);
4884 }
4885 if (arg2->type != XPATH_NUMBER) {
4886 valuePush(ctxt, arg2);
4887 xmlXPathNumberFunction(ctxt, 1);
4888 arg2 = valuePop(ctxt);
4889 }
4890 if (arg2->type != XPATH_NUMBER) {
4891 xmlXPathFreeObject(arg1);
4892 xmlXPathFreeObject(arg2);
4893 XP_ERROR0(XPATH_INVALID_OPERAND);
4894 }
4895 /*
4896 * Add tests for infinity and nan
4897 * => feedback on 3.4 for Inf and NaN
4898 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004899 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00004900 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004901 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004902 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004903 arg1i=xmlXPathIsInf(arg1->floatval);
4904 arg2i=xmlXPathIsInf(arg2->floatval);
4905 if (inf && strict) {
4906 if ((arg1i == -1 && arg2i != -1) ||
4907 (arg2i == 1 && arg1i != 1)) {
4908 ret = 1;
4909 } else if (arg1i == 0 && arg2i == 0) {
4910 ret = (arg1->floatval < arg2->floatval);
4911 } else {
4912 ret = 0;
4913 }
4914 }
4915 else if (inf && !strict) {
4916 if (arg1i == -1 || arg2i == 1) {
4917 ret = 1;
4918 } else if (arg1i == 0 && arg2i == 0) {
4919 ret = (arg1->floatval <= arg2->floatval);
4920 } else {
4921 ret = 0;
4922 }
4923 }
4924 else if (!inf && strict) {
4925 if ((arg1i == 1 && arg2i != 1) ||
4926 (arg2i == -1 && arg1i != -1)) {
4927 ret = 1;
4928 } else if (arg1i == 0 && arg2i == 0) {
4929 ret = (arg1->floatval > arg2->floatval);
4930 } else {
4931 ret = 0;
4932 }
4933 }
4934 else if (!inf && !strict) {
4935 if (arg1i == 1 || arg2i == -1) {
4936 ret = 1;
4937 } else if (arg1i == 0 && arg2i == 0) {
4938 ret = (arg1->floatval >= arg2->floatval);
4939 } else {
4940 ret = 0;
4941 }
4942 }
Daniel Veillard21458c82002-03-27 16:12:22 +00004943 }
Owen Taylor3473f882001-02-23 17:55:21 +00004944 xmlXPathFreeObject(arg1);
4945 xmlXPathFreeObject(arg2);
4946 return(ret);
4947}
4948
4949/**
4950 * xmlXPathValueFlipSign:
4951 * @ctxt: the XPath Parser context
4952 *
4953 * Implement the unary - operation on an XPath object
4954 * The numeric operators convert their operands to numbers as if
4955 * by calling the number function.
4956 */
4957void
4958xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004959 CAST_TO_NUMBER;
4960 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00004961 if (xmlXPathIsNaN(ctxt->value->floatval))
4962 ctxt->value->floatval=xmlXPathNAN;
4963 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
4964 ctxt->value->floatval=xmlXPathNINF;
4965 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
4966 ctxt->value->floatval=xmlXPathPINF;
4967 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00004968 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
4969 ctxt->value->floatval = xmlXPathNZERO;
4970 else
4971 ctxt->value->floatval = 0;
4972 }
4973 else
4974 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00004975}
4976
4977/**
4978 * xmlXPathAddValues:
4979 * @ctxt: the XPath Parser context
4980 *
4981 * Implement the add operation on XPath objects:
4982 * The numeric operators convert their operands to numbers as if
4983 * by calling the number function.
4984 */
4985void
4986xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
4987 xmlXPathObjectPtr arg;
4988 double val;
4989
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004990 arg = valuePop(ctxt);
4991 if (arg == NULL)
4992 XP_ERROR(XPATH_INVALID_OPERAND);
4993 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004994 xmlXPathFreeObject(arg);
4995
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004996 CAST_TO_NUMBER;
4997 CHECK_TYPE(XPATH_NUMBER);
4998 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00004999}
5000
5001/**
5002 * xmlXPathSubValues:
5003 * @ctxt: the XPath Parser context
5004 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005005 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00005006 * The numeric operators convert their operands to numbers as if
5007 * by calling the number function.
5008 */
5009void
5010xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
5011 xmlXPathObjectPtr arg;
5012 double val;
5013
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005014 arg = valuePop(ctxt);
5015 if (arg == NULL)
5016 XP_ERROR(XPATH_INVALID_OPERAND);
5017 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005018 xmlXPathFreeObject(arg);
5019
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005020 CAST_TO_NUMBER;
5021 CHECK_TYPE(XPATH_NUMBER);
5022 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005023}
5024
5025/**
5026 * xmlXPathMultValues:
5027 * @ctxt: the XPath Parser context
5028 *
5029 * Implement the multiply operation on XPath objects:
5030 * The numeric operators convert their operands to numbers as if
5031 * by calling the number function.
5032 */
5033void
5034xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
5035 xmlXPathObjectPtr arg;
5036 double val;
5037
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005038 arg = valuePop(ctxt);
5039 if (arg == NULL)
5040 XP_ERROR(XPATH_INVALID_OPERAND);
5041 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005042 xmlXPathFreeObject(arg);
5043
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005044 CAST_TO_NUMBER;
5045 CHECK_TYPE(XPATH_NUMBER);
5046 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005047}
5048
5049/**
5050 * xmlXPathDivValues:
5051 * @ctxt: the XPath Parser context
5052 *
5053 * Implement the div operation on XPath objects @arg1 / @arg2:
5054 * The numeric operators convert their operands to numbers as if
5055 * by calling the number function.
5056 */
5057void
5058xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
5059 xmlXPathObjectPtr arg;
5060 double val;
5061
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005062 arg = valuePop(ctxt);
5063 if (arg == NULL)
5064 XP_ERROR(XPATH_INVALID_OPERAND);
5065 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005066 xmlXPathFreeObject(arg);
5067
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005068 CAST_TO_NUMBER;
5069 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005070 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
5071 ctxt->value->floatval = xmlXPathNAN;
5072 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005073 if (ctxt->value->floatval == 0)
5074 ctxt->value->floatval = xmlXPathNAN;
5075 else if (ctxt->value->floatval > 0)
5076 ctxt->value->floatval = xmlXPathNINF;
5077 else if (ctxt->value->floatval < 0)
5078 ctxt->value->floatval = xmlXPathPINF;
5079 }
5080 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00005081 if (ctxt->value->floatval == 0)
5082 ctxt->value->floatval = xmlXPathNAN;
5083 else if (ctxt->value->floatval > 0)
5084 ctxt->value->floatval = xmlXPathPINF;
5085 else if (ctxt->value->floatval < 0)
5086 ctxt->value->floatval = xmlXPathNINF;
5087 } else
5088 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005089}
5090
5091/**
5092 * xmlXPathModValues:
5093 * @ctxt: the XPath Parser context
5094 *
5095 * Implement the mod operation on XPath objects: @arg1 / @arg2
5096 * The numeric operators convert their operands to numbers as if
5097 * by calling the number function.
5098 */
5099void
5100xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
5101 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005102 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00005103
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005104 arg = valuePop(ctxt);
5105 if (arg == NULL)
5106 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005107 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005108 xmlXPathFreeObject(arg);
5109
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005110 CAST_TO_NUMBER;
5111 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005112 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00005113 if (arg2 == 0)
5114 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005115 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00005116 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005117 }
Owen Taylor3473f882001-02-23 17:55:21 +00005118}
5119
5120/************************************************************************
5121 * *
5122 * The traversal functions *
5123 * *
5124 ************************************************************************/
5125
Owen Taylor3473f882001-02-23 17:55:21 +00005126/*
5127 * A traversal function enumerates nodes along an axis.
5128 * Initially it must be called with NULL, and it indicates
5129 * termination on the axis by returning NULL.
5130 */
5131typedef xmlNodePtr (*xmlXPathTraversalFunction)
5132 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
5133
5134/**
5135 * xmlXPathNextSelf:
5136 * @ctxt: the XPath Parser context
5137 * @cur: the current node in the traversal
5138 *
5139 * Traversal function for the "self" direction
5140 * The self axis contains just the context node itself
5141 *
5142 * Returns the next element following that axis
5143 */
5144xmlNodePtr
5145xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5146 if (cur == NULL)
5147 return(ctxt->context->node);
5148 return(NULL);
5149}
5150
5151/**
5152 * xmlXPathNextChild:
5153 * @ctxt: the XPath Parser context
5154 * @cur: the current node in the traversal
5155 *
5156 * Traversal function for the "child" direction
5157 * The child axis contains the children of the context node in document order.
5158 *
5159 * Returns the next element following that axis
5160 */
5161xmlNodePtr
5162xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5163 if (cur == NULL) {
5164 if (ctxt->context->node == NULL) return(NULL);
5165 switch (ctxt->context->node->type) {
5166 case XML_ELEMENT_NODE:
5167 case XML_TEXT_NODE:
5168 case XML_CDATA_SECTION_NODE:
5169 case XML_ENTITY_REF_NODE:
5170 case XML_ENTITY_NODE:
5171 case XML_PI_NODE:
5172 case XML_COMMENT_NODE:
5173 case XML_NOTATION_NODE:
5174 case XML_DTD_NODE:
5175 return(ctxt->context->node->children);
5176 case XML_DOCUMENT_NODE:
5177 case XML_DOCUMENT_TYPE_NODE:
5178 case XML_DOCUMENT_FRAG_NODE:
5179 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005180#ifdef LIBXML_DOCB_ENABLED
5181 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005182#endif
5183 return(((xmlDocPtr) ctxt->context->node)->children);
5184 case XML_ELEMENT_DECL:
5185 case XML_ATTRIBUTE_DECL:
5186 case XML_ENTITY_DECL:
5187 case XML_ATTRIBUTE_NODE:
5188 case XML_NAMESPACE_DECL:
5189 case XML_XINCLUDE_START:
5190 case XML_XINCLUDE_END:
5191 return(NULL);
5192 }
5193 return(NULL);
5194 }
5195 if ((cur->type == XML_DOCUMENT_NODE) ||
5196 (cur->type == XML_HTML_DOCUMENT_NODE))
5197 return(NULL);
5198 return(cur->next);
5199}
5200
5201/**
5202 * xmlXPathNextDescendant:
5203 * @ctxt: the XPath Parser context
5204 * @cur: the current node in the traversal
5205 *
5206 * Traversal function for the "descendant" direction
5207 * the descendant axis contains the descendants of the context node in document
5208 * order; a descendant is a child or a child of a child and so on.
5209 *
5210 * Returns the next element following that axis
5211 */
5212xmlNodePtr
5213xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5214 if (cur == NULL) {
5215 if (ctxt->context->node == NULL)
5216 return(NULL);
5217 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5218 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5219 return(NULL);
5220
5221 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5222 return(ctxt->context->doc->children);
5223 return(ctxt->context->node->children);
5224 }
5225
Daniel Veillard567e1b42001-08-01 15:53:47 +00005226 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00005227 /*
5228 * Do not descend on entities declarations
5229 */
5230 if (cur->children->type != XML_ENTITY_DECL) {
5231 cur = cur->children;
5232 /*
5233 * Skip DTDs
5234 */
5235 if (cur->type != XML_DTD_NODE)
5236 return(cur);
5237 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00005238 }
5239
5240 if (cur == ctxt->context->node) return(NULL);
5241
Daniel Veillard68e9e742002-11-16 15:35:11 +00005242 while (cur->next != NULL) {
5243 cur = cur->next;
5244 if ((cur->type != XML_ENTITY_DECL) &&
5245 (cur->type != XML_DTD_NODE))
5246 return(cur);
5247 }
Owen Taylor3473f882001-02-23 17:55:21 +00005248
5249 do {
5250 cur = cur->parent;
5251 if (cur == NULL) return(NULL);
5252 if (cur == ctxt->context->node) return(NULL);
5253 if (cur->next != NULL) {
5254 cur = cur->next;
5255 return(cur);
5256 }
5257 } while (cur != NULL);
5258 return(cur);
5259}
5260
5261/**
5262 * xmlXPathNextDescendantOrSelf:
5263 * @ctxt: the XPath Parser context
5264 * @cur: the current node in the traversal
5265 *
5266 * Traversal function for the "descendant-or-self" direction
5267 * the descendant-or-self axis contains the context node and the descendants
5268 * of the context node in document order; thus the context node is the first
5269 * node on the axis, and the first child of the context node is the second node
5270 * on the axis
5271 *
5272 * Returns the next element following that axis
5273 */
5274xmlNodePtr
5275xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5276 if (cur == NULL) {
5277 if (ctxt->context->node == NULL)
5278 return(NULL);
5279 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5280 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5281 return(NULL);
5282 return(ctxt->context->node);
5283 }
5284
5285 return(xmlXPathNextDescendant(ctxt, cur));
5286}
5287
5288/**
5289 * xmlXPathNextParent:
5290 * @ctxt: the XPath Parser context
5291 * @cur: the current node in the traversal
5292 *
5293 * Traversal function for the "parent" direction
5294 * The parent axis contains the parent of the context node, if there is one.
5295 *
5296 * Returns the next element following that axis
5297 */
5298xmlNodePtr
5299xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5300 /*
5301 * the parent of an attribute or namespace node is the element
5302 * to which the attribute or namespace node is attached
5303 * Namespace handling !!!
5304 */
5305 if (cur == NULL) {
5306 if (ctxt->context->node == NULL) return(NULL);
5307 switch (ctxt->context->node->type) {
5308 case XML_ELEMENT_NODE:
5309 case XML_TEXT_NODE:
5310 case XML_CDATA_SECTION_NODE:
5311 case XML_ENTITY_REF_NODE:
5312 case XML_ENTITY_NODE:
5313 case XML_PI_NODE:
5314 case XML_COMMENT_NODE:
5315 case XML_NOTATION_NODE:
5316 case XML_DTD_NODE:
5317 case XML_ELEMENT_DECL:
5318 case XML_ATTRIBUTE_DECL:
5319 case XML_XINCLUDE_START:
5320 case XML_XINCLUDE_END:
5321 case XML_ENTITY_DECL:
5322 if (ctxt->context->node->parent == NULL)
5323 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005324 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005325 ((ctxt->context->node->parent->name[0] == ' ') ||
5326 (xmlStrEqual(ctxt->context->node->parent->name,
5327 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005328 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005329 return(ctxt->context->node->parent);
5330 case XML_ATTRIBUTE_NODE: {
5331 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5332
5333 return(att->parent);
5334 }
5335 case XML_DOCUMENT_NODE:
5336 case XML_DOCUMENT_TYPE_NODE:
5337 case XML_DOCUMENT_FRAG_NODE:
5338 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005339#ifdef LIBXML_DOCB_ENABLED
5340 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005341#endif
5342 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005343 case XML_NAMESPACE_DECL: {
5344 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5345
5346 if ((ns->next != NULL) &&
5347 (ns->next->type != XML_NAMESPACE_DECL))
5348 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005349 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005350 }
Owen Taylor3473f882001-02-23 17:55:21 +00005351 }
5352 }
5353 return(NULL);
5354}
5355
5356/**
5357 * xmlXPathNextAncestor:
5358 * @ctxt: the XPath Parser context
5359 * @cur: the current node in the traversal
5360 *
5361 * Traversal function for the "ancestor" direction
5362 * the ancestor axis contains the ancestors of the context node; the ancestors
5363 * of the context node consist of the parent of context node and the parent's
5364 * parent and so on; the nodes are ordered in reverse document order; thus the
5365 * parent is the first node on the axis, and the parent's parent is the second
5366 * node on the axis
5367 *
5368 * Returns the next element following that axis
5369 */
5370xmlNodePtr
5371xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5372 /*
5373 * the parent of an attribute or namespace node is the element
5374 * to which the attribute or namespace node is attached
5375 * !!!!!!!!!!!!!
5376 */
5377 if (cur == NULL) {
5378 if (ctxt->context->node == NULL) return(NULL);
5379 switch (ctxt->context->node->type) {
5380 case XML_ELEMENT_NODE:
5381 case XML_TEXT_NODE:
5382 case XML_CDATA_SECTION_NODE:
5383 case XML_ENTITY_REF_NODE:
5384 case XML_ENTITY_NODE:
5385 case XML_PI_NODE:
5386 case XML_COMMENT_NODE:
5387 case XML_DTD_NODE:
5388 case XML_ELEMENT_DECL:
5389 case XML_ATTRIBUTE_DECL:
5390 case XML_ENTITY_DECL:
5391 case XML_NOTATION_NODE:
5392 case XML_XINCLUDE_START:
5393 case XML_XINCLUDE_END:
5394 if (ctxt->context->node->parent == NULL)
5395 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005396 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005397 ((ctxt->context->node->parent->name[0] == ' ') ||
5398 (xmlStrEqual(ctxt->context->node->parent->name,
5399 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005400 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005401 return(ctxt->context->node->parent);
5402 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005403 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005404
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005405 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005406 }
5407 case XML_DOCUMENT_NODE:
5408 case XML_DOCUMENT_TYPE_NODE:
5409 case XML_DOCUMENT_FRAG_NODE:
5410 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005411#ifdef LIBXML_DOCB_ENABLED
5412 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005413#endif
5414 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005415 case XML_NAMESPACE_DECL: {
5416 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5417
5418 if ((ns->next != NULL) &&
5419 (ns->next->type != XML_NAMESPACE_DECL))
5420 return((xmlNodePtr) ns->next);
5421 /* Bad, how did that namespace ended-up there ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005422 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005423 }
Owen Taylor3473f882001-02-23 17:55:21 +00005424 }
5425 return(NULL);
5426 }
5427 if (cur == ctxt->context->doc->children)
5428 return((xmlNodePtr) ctxt->context->doc);
5429 if (cur == (xmlNodePtr) ctxt->context->doc)
5430 return(NULL);
5431 switch (cur->type) {
5432 case XML_ELEMENT_NODE:
5433 case XML_TEXT_NODE:
5434 case XML_CDATA_SECTION_NODE:
5435 case XML_ENTITY_REF_NODE:
5436 case XML_ENTITY_NODE:
5437 case XML_PI_NODE:
5438 case XML_COMMENT_NODE:
5439 case XML_NOTATION_NODE:
5440 case XML_DTD_NODE:
5441 case XML_ELEMENT_DECL:
5442 case XML_ATTRIBUTE_DECL:
5443 case XML_ENTITY_DECL:
5444 case XML_XINCLUDE_START:
5445 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005446 if (cur->parent == NULL)
5447 return(NULL);
5448 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005449 ((cur->parent->name[0] == ' ') ||
5450 (xmlStrEqual(cur->parent->name,
5451 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005452 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005453 return(cur->parent);
5454 case XML_ATTRIBUTE_NODE: {
5455 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5456
5457 return(att->parent);
5458 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005459 case XML_NAMESPACE_DECL: {
5460 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5461
5462 if ((ns->next != NULL) &&
5463 (ns->next->type != XML_NAMESPACE_DECL))
5464 return((xmlNodePtr) ns->next);
5465 /* Bad, how did that namespace ended-up there ? */
5466 return(NULL);
5467 }
Owen Taylor3473f882001-02-23 17:55:21 +00005468 case XML_DOCUMENT_NODE:
5469 case XML_DOCUMENT_TYPE_NODE:
5470 case XML_DOCUMENT_FRAG_NODE:
5471 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005472#ifdef LIBXML_DOCB_ENABLED
5473 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005474#endif
5475 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005476 }
5477 return(NULL);
5478}
5479
5480/**
5481 * xmlXPathNextAncestorOrSelf:
5482 * @ctxt: the XPath Parser context
5483 * @cur: the current node in the traversal
5484 *
5485 * Traversal function for the "ancestor-or-self" direction
5486 * he ancestor-or-self axis contains the context node and ancestors of
5487 * the context node in reverse document order; thus the context node is
5488 * the first node on the axis, and the context node's parent the second;
5489 * parent here is defined the same as with the parent axis.
5490 *
5491 * Returns the next element following that axis
5492 */
5493xmlNodePtr
5494xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5495 if (cur == NULL)
5496 return(ctxt->context->node);
5497 return(xmlXPathNextAncestor(ctxt, cur));
5498}
5499
5500/**
5501 * xmlXPathNextFollowingSibling:
5502 * @ctxt: the XPath Parser context
5503 * @cur: the current node in the traversal
5504 *
5505 * Traversal function for the "following-sibling" direction
5506 * The following-sibling axis contains the following siblings of the context
5507 * node in document order.
5508 *
5509 * Returns the next element following that axis
5510 */
5511xmlNodePtr
5512xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5513 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5514 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5515 return(NULL);
5516 if (cur == (xmlNodePtr) ctxt->context->doc)
5517 return(NULL);
5518 if (cur == NULL)
5519 return(ctxt->context->node->next);
5520 return(cur->next);
5521}
5522
5523/**
5524 * xmlXPathNextPrecedingSibling:
5525 * @ctxt: the XPath Parser context
5526 * @cur: the current node in the traversal
5527 *
5528 * Traversal function for the "preceding-sibling" direction
5529 * The preceding-sibling axis contains the preceding siblings of the context
5530 * node in reverse document order; the first preceding sibling is first on the
5531 * axis; the sibling preceding that node is the second on the axis and so on.
5532 *
5533 * Returns the next element following that axis
5534 */
5535xmlNodePtr
5536xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5537 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5538 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5539 return(NULL);
5540 if (cur == (xmlNodePtr) ctxt->context->doc)
5541 return(NULL);
5542 if (cur == NULL)
5543 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005544 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5545 cur = cur->prev;
5546 if (cur == NULL)
5547 return(ctxt->context->node->prev);
5548 }
Owen Taylor3473f882001-02-23 17:55:21 +00005549 return(cur->prev);
5550}
5551
5552/**
5553 * xmlXPathNextFollowing:
5554 * @ctxt: the XPath Parser context
5555 * @cur: the current node in the traversal
5556 *
5557 * Traversal function for the "following" direction
5558 * The following axis contains all nodes in the same document as the context
5559 * node that are after the context node in document order, excluding any
5560 * descendants and excluding attribute nodes and namespace nodes; the nodes
5561 * are ordered in document order
5562 *
5563 * Returns the next element following that axis
5564 */
5565xmlNodePtr
5566xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5567 if (cur != NULL && cur->children != NULL)
5568 return cur->children ;
5569 if (cur == NULL) cur = ctxt->context->node;
5570 if (cur == NULL) return(NULL) ; /* ERROR */
5571 if (cur->next != NULL) return(cur->next) ;
5572 do {
5573 cur = cur->parent;
5574 if (cur == NULL) return(NULL);
5575 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5576 if (cur->next != NULL) return(cur->next);
5577 } while (cur != NULL);
5578 return(cur);
5579}
5580
5581/*
5582 * xmlXPathIsAncestor:
5583 * @ancestor: the ancestor node
5584 * @node: the current node
5585 *
5586 * Check that @ancestor is a @node's ancestor
5587 *
5588 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5589 */
5590static int
5591xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5592 if ((ancestor == NULL) || (node == NULL)) return(0);
5593 /* nodes need to be in the same document */
5594 if (ancestor->doc != node->doc) return(0);
5595 /* avoid searching if ancestor or node is the root node */
5596 if (ancestor == (xmlNodePtr) node->doc) return(1);
5597 if (node == (xmlNodePtr) ancestor->doc) return(0);
5598 while (node->parent != NULL) {
5599 if (node->parent == ancestor)
5600 return(1);
5601 node = node->parent;
5602 }
5603 return(0);
5604}
5605
5606/**
5607 * xmlXPathNextPreceding:
5608 * @ctxt: the XPath Parser context
5609 * @cur: the current node in the traversal
5610 *
5611 * Traversal function for the "preceding" direction
5612 * the preceding axis contains all nodes in the same document as the context
5613 * node that are before the context node in document order, excluding any
5614 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5615 * ordered in reverse document order
5616 *
5617 * Returns the next element following that axis
5618 */
5619xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005620xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5621{
Owen Taylor3473f882001-02-23 17:55:21 +00005622 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005623 cur = ctxt->context->node;
5624 if (cur == NULL)
5625 return (NULL);
5626 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5627 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005628 do {
5629 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005630 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5631 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005632 }
5633
5634 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005635 if (cur == NULL)
5636 return (NULL);
5637 if (cur == ctxt->context->doc->children)
5638 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005639 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005640 return (cur);
5641}
5642
5643/**
5644 * xmlXPathNextPrecedingInternal:
5645 * @ctxt: the XPath Parser context
5646 * @cur: the current node in the traversal
5647 *
5648 * Traversal function for the "preceding" direction
5649 * the preceding axis contains all nodes in the same document as the context
5650 * node that are before the context node in document order, excluding any
5651 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5652 * ordered in reverse document order
5653 * This is a faster implementation but internal only since it requires a
5654 * state kept in the parser context: ctxt->ancestor.
5655 *
5656 * Returns the next element following that axis
5657 */
5658static xmlNodePtr
5659xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5660 xmlNodePtr cur)
5661{
5662 if (cur == NULL) {
5663 cur = ctxt->context->node;
5664 if (cur == NULL)
5665 return (NULL);
5666 ctxt->ancestor = cur->parent;
5667 }
5668 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5669 cur = cur->prev;
5670 while (cur->prev == NULL) {
5671 cur = cur->parent;
5672 if (cur == NULL)
5673 return (NULL);
5674 if (cur == ctxt->context->doc->children)
5675 return (NULL);
5676 if (cur != ctxt->ancestor)
5677 return (cur);
5678 ctxt->ancestor = cur->parent;
5679 }
5680 cur = cur->prev;
5681 while (cur->last != NULL)
5682 cur = cur->last;
5683 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005684}
5685
5686/**
5687 * xmlXPathNextNamespace:
5688 * @ctxt: the XPath Parser context
5689 * @cur: the current attribute in the traversal
5690 *
5691 * Traversal function for the "namespace" direction
5692 * the namespace axis contains the namespace nodes of the context node;
5693 * the order of nodes on this axis is implementation-defined; the axis will
5694 * be empty unless the context node is an element
5695 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005696 * We keep the XML namespace node at the end of the list.
5697 *
Owen Taylor3473f882001-02-23 17:55:21 +00005698 * Returns the next element following that axis
5699 */
5700xmlNodePtr
5701xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5702 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00005703 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005704 if (ctxt->context->tmpNsList != NULL)
5705 xmlFree(ctxt->context->tmpNsList);
5706 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005707 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005708 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005709 if (ctxt->context->tmpNsList != NULL) {
5710 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
5711 ctxt->context->tmpNsNr++;
5712 }
5713 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005714 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005715 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00005716 if (ctxt->context->tmpNsNr > 0) {
5717 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
5718 } else {
5719 if (ctxt->context->tmpNsList != NULL)
5720 xmlFree(ctxt->context->tmpNsList);
5721 ctxt->context->tmpNsList = NULL;
5722 return(NULL);
5723 }
Owen Taylor3473f882001-02-23 17:55:21 +00005724}
5725
5726/**
5727 * xmlXPathNextAttribute:
5728 * @ctxt: the XPath Parser context
5729 * @cur: the current attribute in the traversal
5730 *
5731 * Traversal function for the "attribute" direction
5732 * TODO: support DTD inherited default attributes
5733 *
5734 * Returns the next element following that axis
5735 */
5736xmlNodePtr
5737xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005738 if (ctxt->context->node == NULL)
5739 return(NULL);
5740 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5741 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005742 if (cur == NULL) {
5743 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5744 return(NULL);
5745 return((xmlNodePtr)ctxt->context->node->properties);
5746 }
5747 return((xmlNodePtr)cur->next);
5748}
5749
5750/************************************************************************
5751 * *
5752 * NodeTest Functions *
5753 * *
5754 ************************************************************************/
5755
Owen Taylor3473f882001-02-23 17:55:21 +00005756#define IS_FUNCTION 200
5757
Owen Taylor3473f882001-02-23 17:55:21 +00005758
5759/************************************************************************
5760 * *
5761 * Implicit tree core function library *
5762 * *
5763 ************************************************************************/
5764
5765/**
5766 * xmlXPathRoot:
5767 * @ctxt: the XPath Parser context
5768 *
5769 * Initialize the context to the root of the document
5770 */
5771void
5772xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5773 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5774 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5775}
5776
5777/************************************************************************
5778 * *
5779 * The explicit core function library *
5780 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5781 * *
5782 ************************************************************************/
5783
5784
5785/**
5786 * xmlXPathLastFunction:
5787 * @ctxt: the XPath Parser context
5788 * @nargs: the number of arguments
5789 *
5790 * Implement the last() XPath function
5791 * number last()
5792 * The last function returns the number of nodes in the context node list.
5793 */
5794void
5795xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5796 CHECK_ARITY(0);
5797 if (ctxt->context->contextSize >= 0) {
5798 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5799#ifdef DEBUG_EXPR
5800 xmlGenericError(xmlGenericErrorContext,
5801 "last() : %d\n", ctxt->context->contextSize);
5802#endif
5803 } else {
5804 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5805 }
5806}
5807
5808/**
5809 * xmlXPathPositionFunction:
5810 * @ctxt: the XPath Parser context
5811 * @nargs: the number of arguments
5812 *
5813 * Implement the position() XPath function
5814 * number position()
5815 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005816 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00005817 * will be equal to last().
5818 */
5819void
5820xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5821 CHECK_ARITY(0);
5822 if (ctxt->context->proximityPosition >= 0) {
5823 valuePush(ctxt,
5824 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5825#ifdef DEBUG_EXPR
5826 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5827 ctxt->context->proximityPosition);
5828#endif
5829 } else {
5830 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5831 }
5832}
5833
5834/**
5835 * xmlXPathCountFunction:
5836 * @ctxt: the XPath Parser context
5837 * @nargs: the number of arguments
5838 *
5839 * Implement the count() XPath function
5840 * number count(node-set)
5841 */
5842void
5843xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5844 xmlXPathObjectPtr cur;
5845
5846 CHECK_ARITY(1);
5847 if ((ctxt->value == NULL) ||
5848 ((ctxt->value->type != XPATH_NODESET) &&
5849 (ctxt->value->type != XPATH_XSLT_TREE)))
5850 XP_ERROR(XPATH_INVALID_TYPE);
5851 cur = valuePop(ctxt);
5852
Daniel Veillard911f49a2001-04-07 15:39:35 +00005853 if ((cur == NULL) || (cur->nodesetval == NULL))
5854 valuePush(ctxt, xmlXPathNewFloat((double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00005855 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00005856 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00005857 } else {
5858 if ((cur->nodesetval->nodeNr != 1) ||
5859 (cur->nodesetval->nodeTab == NULL)) {
5860 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5861 } else {
5862 xmlNodePtr tmp;
5863 int i = 0;
5864
5865 tmp = cur->nodesetval->nodeTab[0];
5866 if (tmp != NULL) {
5867 tmp = tmp->children;
5868 while (tmp != NULL) {
5869 tmp = tmp->next;
5870 i++;
5871 }
5872 }
5873 valuePush(ctxt, xmlXPathNewFloat((double) i));
5874 }
5875 }
Owen Taylor3473f882001-02-23 17:55:21 +00005876 xmlXPathFreeObject(cur);
5877}
5878
5879/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005880 * xmlXPathGetElementsByIds:
5881 * @doc: the document
5882 * @ids: a whitespace separated list of IDs
5883 *
5884 * Selects elements by their unique ID.
5885 *
5886 * Returns a node-set of selected elements.
5887 */
5888static xmlNodeSetPtr
5889xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5890 xmlNodeSetPtr ret;
5891 const xmlChar *cur = ids;
5892 xmlChar *ID;
5893 xmlAttrPtr attr;
5894 xmlNodePtr elem = NULL;
5895
5896 ret = xmlXPathNodeSetCreate(NULL);
5897
5898 while (IS_BLANK(*cur)) cur++;
5899 while (*cur != 0) {
5900 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
5901 (*cur == '.') || (*cur == '-') ||
5902 (*cur == '_') || (*cur == ':') ||
5903 (IS_COMBINING(*cur)) ||
5904 (IS_EXTENDER(*cur)))
5905 cur++;
5906
5907 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
5908
5909 ID = xmlStrndup(ids, cur - ids);
5910 attr = xmlGetID(doc, ID);
5911 if (attr != NULL) {
5912 elem = attr->parent;
5913 xmlXPathNodeSetAdd(ret, elem);
5914 }
5915 if (ID != NULL)
5916 xmlFree(ID);
5917
5918 while (IS_BLANK(*cur)) cur++;
5919 ids = cur;
5920 }
5921 return(ret);
5922}
5923
5924/**
Owen Taylor3473f882001-02-23 17:55:21 +00005925 * xmlXPathIdFunction:
5926 * @ctxt: the XPath Parser context
5927 * @nargs: the number of arguments
5928 *
5929 * Implement the id() XPath function
5930 * node-set id(object)
5931 * The id function selects elements by their unique ID
5932 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
5933 * then the result is the union of the result of applying id to the
5934 * string value of each of the nodes in the argument node-set. When the
5935 * argument to id is of any other type, the argument is converted to a
5936 * string as if by a call to the string function; the string is split
5937 * into a whitespace-separated list of tokens (whitespace is any sequence
5938 * of characters matching the production S); the result is a node-set
5939 * containing the elements in the same document as the context node that
5940 * have a unique ID equal to any of the tokens in the list.
5941 */
5942void
5943xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005944 xmlChar *tokens;
5945 xmlNodeSetPtr ret;
5946 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00005947
5948 CHECK_ARITY(1);
5949 obj = valuePop(ctxt);
5950 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00005951 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005952 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00005953 int i;
5954
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005955 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005956
Daniel Veillard911f49a2001-04-07 15:39:35 +00005957 if (obj->nodesetval != NULL) {
5958 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005959 tokens =
5960 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
5961 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
5962 ret = xmlXPathNodeSetMerge(ret, ns);
5963 xmlXPathFreeNodeSet(ns);
5964 if (tokens != NULL)
5965 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00005966 }
Owen Taylor3473f882001-02-23 17:55:21 +00005967 }
5968
5969 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005970 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005971 return;
5972 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005973 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00005974
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005975 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
5976 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005977
Owen Taylor3473f882001-02-23 17:55:21 +00005978 xmlXPathFreeObject(obj);
5979 return;
5980}
5981
5982/**
5983 * xmlXPathLocalNameFunction:
5984 * @ctxt: the XPath Parser context
5985 * @nargs: the number of arguments
5986 *
5987 * Implement the local-name() XPath function
5988 * string local-name(node-set?)
5989 * The local-name function returns a string containing the local part
5990 * of the name of the node in the argument node-set that is first in
5991 * document order. If the node-set is empty or the first node has no
5992 * name, an empty string is returned. If the argument is omitted it
5993 * defaults to the context node.
5994 */
5995void
5996xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5997 xmlXPathObjectPtr cur;
5998
5999 if (nargs == 0) {
6000 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6001 nargs = 1;
6002 }
6003
6004 CHECK_ARITY(1);
6005 if ((ctxt->value == NULL) ||
6006 ((ctxt->value->type != XPATH_NODESET) &&
6007 (ctxt->value->type != XPATH_XSLT_TREE)))
6008 XP_ERROR(XPATH_INVALID_TYPE);
6009 cur = valuePop(ctxt);
6010
Daniel Veillard911f49a2001-04-07 15:39:35 +00006011 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006012 valuePush(ctxt, xmlXPathNewCString(""));
6013 } else {
6014 int i = 0; /* Should be first in document order !!!!! */
6015 switch (cur->nodesetval->nodeTab[i]->type) {
6016 case XML_ELEMENT_NODE:
6017 case XML_ATTRIBUTE_NODE:
6018 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006019 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6020 valuePush(ctxt, xmlXPathNewCString(""));
6021 else
6022 valuePush(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006023 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
6024 break;
6025 case XML_NAMESPACE_DECL:
6026 valuePush(ctxt, xmlXPathNewString(
6027 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
6028 break;
6029 default:
6030 valuePush(ctxt, xmlXPathNewCString(""));
6031 }
6032 }
6033 xmlXPathFreeObject(cur);
6034}
6035
6036/**
6037 * xmlXPathNamespaceURIFunction:
6038 * @ctxt: the XPath Parser context
6039 * @nargs: the number of arguments
6040 *
6041 * Implement the namespace-uri() XPath function
6042 * string namespace-uri(node-set?)
6043 * The namespace-uri function returns a string containing the
6044 * namespace URI of the expanded name of the node in the argument
6045 * node-set that is first in document order. If the node-set is empty,
6046 * the first node has no name, or the expanded name has no namespace
6047 * URI, an empty string is returned. If the argument is omitted it
6048 * defaults to the context node.
6049 */
6050void
6051xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6052 xmlXPathObjectPtr cur;
6053
6054 if (nargs == 0) {
6055 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6056 nargs = 1;
6057 }
6058 CHECK_ARITY(1);
6059 if ((ctxt->value == NULL) ||
6060 ((ctxt->value->type != XPATH_NODESET) &&
6061 (ctxt->value->type != XPATH_XSLT_TREE)))
6062 XP_ERROR(XPATH_INVALID_TYPE);
6063 cur = valuePop(ctxt);
6064
Daniel Veillard911f49a2001-04-07 15:39:35 +00006065 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006066 valuePush(ctxt, xmlXPathNewCString(""));
6067 } else {
6068 int i = 0; /* Should be first in document order !!!!! */
6069 switch (cur->nodesetval->nodeTab[i]->type) {
6070 case XML_ELEMENT_NODE:
6071 case XML_ATTRIBUTE_NODE:
6072 if (cur->nodesetval->nodeTab[i]->ns == NULL)
6073 valuePush(ctxt, xmlXPathNewCString(""));
6074 else
6075 valuePush(ctxt, xmlXPathNewString(
6076 cur->nodesetval->nodeTab[i]->ns->href));
6077 break;
6078 default:
6079 valuePush(ctxt, xmlXPathNewCString(""));
6080 }
6081 }
6082 xmlXPathFreeObject(cur);
6083}
6084
6085/**
6086 * xmlXPathNameFunction:
6087 * @ctxt: the XPath Parser context
6088 * @nargs: the number of arguments
6089 *
6090 * Implement the name() XPath function
6091 * string name(node-set?)
6092 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006093 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00006094 * order. The QName must represent the name with respect to the namespace
6095 * declarations in effect on the node whose name is being represented.
6096 * Typically, this will be the form in which the name occurred in the XML
6097 * source. This need not be the case if there are namespace declarations
6098 * in effect on the node that associate multiple prefixes with the same
6099 * namespace. However, an implementation may include information about
6100 * the original prefix in its representation of nodes; in this case, an
6101 * implementation can ensure that the returned string is always the same
6102 * as the QName used in the XML source. If the argument it omitted it
6103 * defaults to the context node.
6104 * Libxml keep the original prefix so the "real qualified name" used is
6105 * returned.
6106 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006107static void
Daniel Veillard04383752001-07-08 14:27:15 +00006108xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
6109{
Owen Taylor3473f882001-02-23 17:55:21 +00006110 xmlXPathObjectPtr cur;
6111
6112 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00006113 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6114 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006115 }
6116
6117 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00006118 if ((ctxt->value == NULL) ||
6119 ((ctxt->value->type != XPATH_NODESET) &&
6120 (ctxt->value->type != XPATH_XSLT_TREE)))
6121 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006122 cur = valuePop(ctxt);
6123
Daniel Veillard911f49a2001-04-07 15:39:35 +00006124 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006125 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00006126 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006127 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00006128
Daniel Veillard04383752001-07-08 14:27:15 +00006129 switch (cur->nodesetval->nodeTab[i]->type) {
6130 case XML_ELEMENT_NODE:
6131 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006132 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6133 valuePush(ctxt, xmlXPathNewCString(""));
6134 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6135 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006136 valuePush(ctxt,
6137 xmlXPathNewString(cur->nodesetval->
6138 nodeTab[i]->name));
6139
Daniel Veillard652d8a92003-02-04 19:28:49 +00006140 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006141 char name[2000];
6142
6143 snprintf(name, sizeof(name), "%s:%s",
6144 (char *) cur->nodesetval->nodeTab[i]->ns->
6145 prefix,
6146 (char *) cur->nodesetval->nodeTab[i]->name);
6147 name[sizeof(name) - 1] = 0;
6148 valuePush(ctxt, xmlXPathNewCString(name));
6149 }
6150 break;
6151 default:
6152 valuePush(ctxt,
6153 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6154 xmlXPathLocalNameFunction(ctxt, 1);
6155 }
Owen Taylor3473f882001-02-23 17:55:21 +00006156 }
6157 xmlXPathFreeObject(cur);
6158}
6159
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006160
6161/**
Owen Taylor3473f882001-02-23 17:55:21 +00006162 * xmlXPathStringFunction:
6163 * @ctxt: the XPath Parser context
6164 * @nargs: the number of arguments
6165 *
6166 * Implement the string() XPath function
6167 * string string(object?)
6168 * he string function converts an object to a string as follows:
6169 * - A node-set is converted to a string by returning the value of
6170 * the node in the node-set that is first in document order.
6171 * If the node-set is empty, an empty string is returned.
6172 * - A number is converted to a string as follows
6173 * + NaN is converted to the string NaN
6174 * + positive zero is converted to the string 0
6175 * + negative zero is converted to the string 0
6176 * + positive infinity is converted to the string Infinity
6177 * + negative infinity is converted to the string -Infinity
6178 * + if the number is an integer, the number is represented in
6179 * decimal form as a Number with no decimal point and no leading
6180 * zeros, preceded by a minus sign (-) if the number is negative
6181 * + otherwise, the number is represented in decimal form as a
6182 * Number including a decimal point with at least one digit
6183 * before the decimal point and at least one digit after the
6184 * decimal point, preceded by a minus sign (-) if the number
6185 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006186 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00006187 * before the decimal point; beyond the one required digit
6188 * after the decimal point there must be as many, but only as
6189 * many, more digits as are needed to uniquely distinguish the
6190 * number from all other IEEE 754 numeric values.
6191 * - The boolean false value is converted to the string false.
6192 * The boolean true value is converted to the string true.
6193 *
6194 * If the argument is omitted, it defaults to a node-set with the
6195 * context node as its only member.
6196 */
6197void
6198xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6199 xmlXPathObjectPtr cur;
6200
6201 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006202 valuePush(ctxt,
6203 xmlXPathWrapString(
6204 xmlXPathCastNodeToString(ctxt->context->node)));
6205 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006206 }
6207
6208 CHECK_ARITY(1);
6209 cur = valuePop(ctxt);
6210 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006211 cur = xmlXPathConvertString(cur);
6212 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006213}
6214
6215/**
6216 * xmlXPathStringLengthFunction:
6217 * @ctxt: the XPath Parser context
6218 * @nargs: the number of arguments
6219 *
6220 * Implement the string-length() XPath function
6221 * number string-length(string?)
6222 * The string-length returns the number of characters in the string
6223 * (see [3.6 Strings]). If the argument is omitted, it defaults to
6224 * the context node converted to a string, in other words the value
6225 * of the context node.
6226 */
6227void
6228xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6229 xmlXPathObjectPtr cur;
6230
6231 if (nargs == 0) {
6232 if (ctxt->context->node == NULL) {
6233 valuePush(ctxt, xmlXPathNewFloat(0));
6234 } else {
6235 xmlChar *content;
6236
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006237 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006238 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00006239 xmlFree(content);
6240 }
6241 return;
6242 }
6243 CHECK_ARITY(1);
6244 CAST_TO_STRING;
6245 CHECK_TYPE(XPATH_STRING);
6246 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006247 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00006248 xmlXPathFreeObject(cur);
6249}
6250
6251/**
6252 * xmlXPathConcatFunction:
6253 * @ctxt: the XPath Parser context
6254 * @nargs: the number of arguments
6255 *
6256 * Implement the concat() XPath function
6257 * string concat(string, string, string*)
6258 * The concat function returns the concatenation of its arguments.
6259 */
6260void
6261xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6262 xmlXPathObjectPtr cur, newobj;
6263 xmlChar *tmp;
6264
6265 if (nargs < 2) {
6266 CHECK_ARITY(2);
6267 }
6268
6269 CAST_TO_STRING;
6270 cur = valuePop(ctxt);
6271 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6272 xmlXPathFreeObject(cur);
6273 return;
6274 }
6275 nargs--;
6276
6277 while (nargs > 0) {
6278 CAST_TO_STRING;
6279 newobj = valuePop(ctxt);
6280 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6281 xmlXPathFreeObject(newobj);
6282 xmlXPathFreeObject(cur);
6283 XP_ERROR(XPATH_INVALID_TYPE);
6284 }
6285 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6286 newobj->stringval = cur->stringval;
6287 cur->stringval = tmp;
6288
6289 xmlXPathFreeObject(newobj);
6290 nargs--;
6291 }
6292 valuePush(ctxt, cur);
6293}
6294
6295/**
6296 * xmlXPathContainsFunction:
6297 * @ctxt: the XPath Parser context
6298 * @nargs: the number of arguments
6299 *
6300 * Implement the contains() XPath function
6301 * boolean contains(string, string)
6302 * The contains function returns true if the first argument string
6303 * contains the second argument string, and otherwise returns false.
6304 */
6305void
6306xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6307 xmlXPathObjectPtr hay, needle;
6308
6309 CHECK_ARITY(2);
6310 CAST_TO_STRING;
6311 CHECK_TYPE(XPATH_STRING);
6312 needle = valuePop(ctxt);
6313 CAST_TO_STRING;
6314 hay = valuePop(ctxt);
6315 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6316 xmlXPathFreeObject(hay);
6317 xmlXPathFreeObject(needle);
6318 XP_ERROR(XPATH_INVALID_TYPE);
6319 }
6320 if (xmlStrstr(hay->stringval, needle->stringval))
6321 valuePush(ctxt, xmlXPathNewBoolean(1));
6322 else
6323 valuePush(ctxt, xmlXPathNewBoolean(0));
6324 xmlXPathFreeObject(hay);
6325 xmlXPathFreeObject(needle);
6326}
6327
6328/**
6329 * xmlXPathStartsWithFunction:
6330 * @ctxt: the XPath Parser context
6331 * @nargs: the number of arguments
6332 *
6333 * Implement the starts-with() XPath function
6334 * boolean starts-with(string, string)
6335 * The starts-with function returns true if the first argument string
6336 * starts with the second argument string, and otherwise returns false.
6337 */
6338void
6339xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6340 xmlXPathObjectPtr hay, needle;
6341 int n;
6342
6343 CHECK_ARITY(2);
6344 CAST_TO_STRING;
6345 CHECK_TYPE(XPATH_STRING);
6346 needle = valuePop(ctxt);
6347 CAST_TO_STRING;
6348 hay = valuePop(ctxt);
6349 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6350 xmlXPathFreeObject(hay);
6351 xmlXPathFreeObject(needle);
6352 XP_ERROR(XPATH_INVALID_TYPE);
6353 }
6354 n = xmlStrlen(needle->stringval);
6355 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6356 valuePush(ctxt, xmlXPathNewBoolean(0));
6357 else
6358 valuePush(ctxt, xmlXPathNewBoolean(1));
6359 xmlXPathFreeObject(hay);
6360 xmlXPathFreeObject(needle);
6361}
6362
6363/**
6364 * xmlXPathSubstringFunction:
6365 * @ctxt: the XPath Parser context
6366 * @nargs: the number of arguments
6367 *
6368 * Implement the substring() XPath function
6369 * string substring(string, number, number?)
6370 * The substring function returns the substring of the first argument
6371 * starting at the position specified in the second argument with
6372 * length specified in the third argument. For example,
6373 * substring("12345",2,3) returns "234". If the third argument is not
6374 * specified, it returns the substring starting at the position specified
6375 * in the second argument and continuing to the end of the string. For
6376 * example, substring("12345",2) returns "2345". More precisely, each
6377 * character in the string (see [3.6 Strings]) is considered to have a
6378 * numeric position: the position of the first character is 1, the position
6379 * of the second character is 2 and so on. The returned substring contains
6380 * those characters for which the position of the character is greater than
6381 * or equal to the second argument and, if the third argument is specified,
6382 * less than the sum of the second and third arguments; the comparisons
6383 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6384 * - substring("12345", 1.5, 2.6) returns "234"
6385 * - substring("12345", 0, 3) returns "12"
6386 * - substring("12345", 0 div 0, 3) returns ""
6387 * - substring("12345", 1, 0 div 0) returns ""
6388 * - substring("12345", -42, 1 div 0) returns "12345"
6389 * - substring("12345", -1 div 0, 1 div 0) returns ""
6390 */
6391void
6392xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6393 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006394 double le=0, in;
6395 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006396 xmlChar *ret;
6397
Owen Taylor3473f882001-02-23 17:55:21 +00006398 if (nargs < 2) {
6399 CHECK_ARITY(2);
6400 }
6401 if (nargs > 3) {
6402 CHECK_ARITY(3);
6403 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006404 /*
6405 * take care of possible last (position) argument
6406 */
Owen Taylor3473f882001-02-23 17:55:21 +00006407 if (nargs == 3) {
6408 CAST_TO_NUMBER;
6409 CHECK_TYPE(XPATH_NUMBER);
6410 len = valuePop(ctxt);
6411 le = len->floatval;
6412 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006413 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006414
Owen Taylor3473f882001-02-23 17:55:21 +00006415 CAST_TO_NUMBER;
6416 CHECK_TYPE(XPATH_NUMBER);
6417 start = valuePop(ctxt);
6418 in = start->floatval;
6419 xmlXPathFreeObject(start);
6420 CAST_TO_STRING;
6421 CHECK_TYPE(XPATH_STRING);
6422 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006423 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006424
Daniel Veillard97ac1312001-05-30 19:14:17 +00006425 /*
6426 * If last pos not present, calculate last position
6427 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006428 if (nargs != 3) {
6429 le = (double)m;
6430 if (in < 1.0)
6431 in = 1.0;
6432 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006433
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006434 /* Need to check for the special cases where either
6435 * the index is NaN, the length is NaN, or both
6436 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00006437 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006438 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006439 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00006440 * To meet the requirements of the spec, the arguments
6441 * must be converted to integer format before
6442 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006443 *
Daniel Veillard9e412302002-06-10 15:59:44 +00006444 * First we go to integer form, rounding up
6445 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006446 */
6447 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00006448 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00006449
Daniel Veillard9e412302002-06-10 15:59:44 +00006450 if (xmlXPathIsInf(le) == 1) {
6451 l = m;
6452 if (i < 1)
6453 i = 1;
6454 }
6455 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
6456 l = 0;
6457 else {
6458 l = (int) le;
6459 if (((double)l)+0.5 <= le) l++;
6460 }
6461
6462 /* Now we normalize inidices */
6463 i -= 1;
6464 l += i;
6465 if (i < 0)
6466 i = 0;
6467 if (l > m)
6468 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00006469
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006470 /* number of chars to copy */
6471 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00006472
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006473 ret = xmlUTF8Strsub(str->stringval, i, l);
6474 }
6475 else {
6476 ret = NULL;
6477 }
6478
Owen Taylor3473f882001-02-23 17:55:21 +00006479 if (ret == NULL)
6480 valuePush(ctxt, xmlXPathNewCString(""));
6481 else {
6482 valuePush(ctxt, xmlXPathNewString(ret));
6483 xmlFree(ret);
6484 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006485
Owen Taylor3473f882001-02-23 17:55:21 +00006486 xmlXPathFreeObject(str);
6487}
6488
6489/**
6490 * xmlXPathSubstringBeforeFunction:
6491 * @ctxt: the XPath Parser context
6492 * @nargs: the number of arguments
6493 *
6494 * Implement the substring-before() XPath function
6495 * string substring-before(string, string)
6496 * The substring-before function returns the substring of the first
6497 * argument string that precedes the first occurrence of the second
6498 * argument string in the first argument string, or the empty string
6499 * if the first argument string does not contain the second argument
6500 * string. For example, substring-before("1999/04/01","/") returns 1999.
6501 */
6502void
6503xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6504 xmlXPathObjectPtr str;
6505 xmlXPathObjectPtr find;
6506 xmlBufferPtr target;
6507 const xmlChar *point;
6508 int offset;
6509
6510 CHECK_ARITY(2);
6511 CAST_TO_STRING;
6512 find = valuePop(ctxt);
6513 CAST_TO_STRING;
6514 str = valuePop(ctxt);
6515
6516 target = xmlBufferCreate();
6517 if (target) {
6518 point = xmlStrstr(str->stringval, find->stringval);
6519 if (point) {
6520 offset = (int)(point - str->stringval);
6521 xmlBufferAdd(target, str->stringval, offset);
6522 }
6523 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6524 xmlBufferFree(target);
6525 }
6526
6527 xmlXPathFreeObject(str);
6528 xmlXPathFreeObject(find);
6529}
6530
6531/**
6532 * xmlXPathSubstringAfterFunction:
6533 * @ctxt: the XPath Parser context
6534 * @nargs: the number of arguments
6535 *
6536 * Implement the substring-after() XPath function
6537 * string substring-after(string, string)
6538 * The substring-after function returns the substring of the first
6539 * argument string that follows the first occurrence of the second
6540 * argument string in the first argument string, or the empty stringi
6541 * if the first argument string does not contain the second argument
6542 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6543 * and substring-after("1999/04/01","19") returns 99/04/01.
6544 */
6545void
6546xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6547 xmlXPathObjectPtr str;
6548 xmlXPathObjectPtr find;
6549 xmlBufferPtr target;
6550 const xmlChar *point;
6551 int offset;
6552
6553 CHECK_ARITY(2);
6554 CAST_TO_STRING;
6555 find = valuePop(ctxt);
6556 CAST_TO_STRING;
6557 str = valuePop(ctxt);
6558
6559 target = xmlBufferCreate();
6560 if (target) {
6561 point = xmlStrstr(str->stringval, find->stringval);
6562 if (point) {
6563 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6564 xmlBufferAdd(target, &str->stringval[offset],
6565 xmlStrlen(str->stringval) - offset);
6566 }
6567 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6568 xmlBufferFree(target);
6569 }
6570
6571 xmlXPathFreeObject(str);
6572 xmlXPathFreeObject(find);
6573}
6574
6575/**
6576 * xmlXPathNormalizeFunction:
6577 * @ctxt: the XPath Parser context
6578 * @nargs: the number of arguments
6579 *
6580 * Implement the normalize-space() XPath function
6581 * string normalize-space(string?)
6582 * The normalize-space function returns the argument string with white
6583 * space normalized by stripping leading and trailing whitespace
6584 * and replacing sequences of whitespace characters by a single
6585 * space. Whitespace characters are the same allowed by the S production
6586 * in XML. If the argument is omitted, it defaults to the context
6587 * node converted to a string, in other words the value of the context node.
6588 */
6589void
6590xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6591 xmlXPathObjectPtr obj = NULL;
6592 xmlChar *source = NULL;
6593 xmlBufferPtr target;
6594 xmlChar blank;
6595
6596 if (nargs == 0) {
6597 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006598 valuePush(ctxt,
6599 xmlXPathWrapString(
6600 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006601 nargs = 1;
6602 }
6603
6604 CHECK_ARITY(1);
6605 CAST_TO_STRING;
6606 CHECK_TYPE(XPATH_STRING);
6607 obj = valuePop(ctxt);
6608 source = obj->stringval;
6609
6610 target = xmlBufferCreate();
6611 if (target && source) {
6612
6613 /* Skip leading whitespaces */
6614 while (IS_BLANK(*source))
6615 source++;
6616
6617 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6618 blank = 0;
6619 while (*source) {
6620 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006621 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006622 } else {
6623 if (blank) {
6624 xmlBufferAdd(target, &blank, 1);
6625 blank = 0;
6626 }
6627 xmlBufferAdd(target, source, 1);
6628 }
6629 source++;
6630 }
6631
6632 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6633 xmlBufferFree(target);
6634 }
6635 xmlXPathFreeObject(obj);
6636}
6637
6638/**
6639 * xmlXPathTranslateFunction:
6640 * @ctxt: the XPath Parser context
6641 * @nargs: the number of arguments
6642 *
6643 * Implement the translate() XPath function
6644 * string translate(string, string, string)
6645 * The translate function returns the first argument string with
6646 * occurrences of characters in the second argument string replaced
6647 * by the character at the corresponding position in the third argument
6648 * string. For example, translate("bar","abc","ABC") returns the string
6649 * BAr. If there is a character in the second argument string with no
6650 * character at a corresponding position in the third argument string
6651 * (because the second argument string is longer than the third argument
6652 * string), then occurrences of that character in the first argument
6653 * string are removed. For example, translate("--aaa--","abc-","ABC")
6654 * returns "AAA". If a character occurs more than once in second
6655 * argument string, then the first occurrence determines the replacement
6656 * character. If the third argument string is longer than the second
6657 * argument string, then excess characters are ignored.
6658 */
6659void
6660xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006661 xmlXPathObjectPtr str;
6662 xmlXPathObjectPtr from;
6663 xmlXPathObjectPtr to;
6664 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006665 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006666 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006667 xmlChar *point;
6668 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006669
Daniel Veillarde043ee12001-04-16 14:08:07 +00006670 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006671
Daniel Veillarde043ee12001-04-16 14:08:07 +00006672 CAST_TO_STRING;
6673 to = valuePop(ctxt);
6674 CAST_TO_STRING;
6675 from = valuePop(ctxt);
6676 CAST_TO_STRING;
6677 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006678
Daniel Veillarde043ee12001-04-16 14:08:07 +00006679 target = xmlBufferCreate();
6680 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006681 max = xmlUTF8Strlen(to->stringval);
6682 for (cptr = str->stringval; (ch=*cptr); ) {
6683 offset = xmlUTF8Strloc(from->stringval, cptr);
6684 if (offset >= 0) {
6685 if (offset < max) {
6686 point = xmlUTF8Strpos(to->stringval, offset);
6687 if (point)
6688 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6689 }
6690 } else
6691 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6692
6693 /* Step to next character in input */
6694 cptr++;
6695 if ( ch & 0x80 ) {
6696 /* if not simple ascii, verify proper format */
6697 if ( (ch & 0xc0) != 0xc0 ) {
6698 xmlGenericError(xmlGenericErrorContext,
6699 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6700 break;
6701 }
6702 /* then skip over remaining bytes for this char */
6703 while ( (ch <<= 1) & 0x80 )
6704 if ( (*cptr++ & 0xc0) != 0x80 ) {
6705 xmlGenericError(xmlGenericErrorContext,
6706 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6707 break;
6708 }
6709 if (ch & 0x80) /* must have had error encountered */
6710 break;
6711 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006712 }
Owen Taylor3473f882001-02-23 17:55:21 +00006713 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006714 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6715 xmlBufferFree(target);
6716 xmlXPathFreeObject(str);
6717 xmlXPathFreeObject(from);
6718 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006719}
6720
6721/**
6722 * xmlXPathBooleanFunction:
6723 * @ctxt: the XPath Parser context
6724 * @nargs: the number of arguments
6725 *
6726 * Implement the boolean() XPath function
6727 * boolean boolean(object)
6728 * he boolean function converts its argument to a boolean as follows:
6729 * - a number is true if and only if it is neither positive or
6730 * negative zero nor NaN
6731 * - a node-set is true if and only if it is non-empty
6732 * - a string is true if and only if its length is non-zero
6733 */
6734void
6735xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6736 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006737
6738 CHECK_ARITY(1);
6739 cur = valuePop(ctxt);
6740 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006741 cur = xmlXPathConvertBoolean(cur);
6742 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006743}
6744
6745/**
6746 * xmlXPathNotFunction:
6747 * @ctxt: the XPath Parser context
6748 * @nargs: the number of arguments
6749 *
6750 * Implement the not() XPath function
6751 * boolean not(boolean)
6752 * The not function returns true if its argument is false,
6753 * and false otherwise.
6754 */
6755void
6756xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6757 CHECK_ARITY(1);
6758 CAST_TO_BOOLEAN;
6759 CHECK_TYPE(XPATH_BOOLEAN);
6760 ctxt->value->boolval = ! ctxt->value->boolval;
6761}
6762
6763/**
6764 * xmlXPathTrueFunction:
6765 * @ctxt: the XPath Parser context
6766 * @nargs: the number of arguments
6767 *
6768 * Implement the true() XPath function
6769 * boolean true()
6770 */
6771void
6772xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6773 CHECK_ARITY(0);
6774 valuePush(ctxt, xmlXPathNewBoolean(1));
6775}
6776
6777/**
6778 * xmlXPathFalseFunction:
6779 * @ctxt: the XPath Parser context
6780 * @nargs: the number of arguments
6781 *
6782 * Implement the false() XPath function
6783 * boolean false()
6784 */
6785void
6786xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6787 CHECK_ARITY(0);
6788 valuePush(ctxt, xmlXPathNewBoolean(0));
6789}
6790
6791/**
6792 * xmlXPathLangFunction:
6793 * @ctxt: the XPath Parser context
6794 * @nargs: the number of arguments
6795 *
6796 * Implement the lang() XPath function
6797 * boolean lang(string)
6798 * The lang function returns true or false depending on whether the
6799 * language of the context node as specified by xml:lang attributes
6800 * is the same as or is a sublanguage of the language specified by
6801 * the argument string. The language of the context node is determined
6802 * by the value of the xml:lang attribute on the context node, or, if
6803 * the context node has no xml:lang attribute, by the value of the
6804 * xml:lang attribute on the nearest ancestor of the context node that
6805 * has an xml:lang attribute. If there is no such attribute, then lang
6806 * returns false. If there is such an attribute, then lang returns
6807 * true if the attribute value is equal to the argument ignoring case,
6808 * or if there is some suffix starting with - such that the attribute
6809 * value is equal to the argument ignoring that suffix of the attribute
6810 * value and ignoring case.
6811 */
6812void
6813xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6814 xmlXPathObjectPtr val;
6815 const xmlChar *theLang;
6816 const xmlChar *lang;
6817 int ret = 0;
6818 int i;
6819
6820 CHECK_ARITY(1);
6821 CAST_TO_STRING;
6822 CHECK_TYPE(XPATH_STRING);
6823 val = valuePop(ctxt);
6824 lang = val->stringval;
6825 theLang = xmlNodeGetLang(ctxt->context->node);
6826 if ((theLang != NULL) && (lang != NULL)) {
6827 for (i = 0;lang[i] != 0;i++)
6828 if (toupper(lang[i]) != toupper(theLang[i]))
6829 goto not_equal;
6830 ret = 1;
6831 }
6832not_equal:
6833 xmlXPathFreeObject(val);
6834 valuePush(ctxt, xmlXPathNewBoolean(ret));
6835}
6836
6837/**
6838 * xmlXPathNumberFunction:
6839 * @ctxt: the XPath Parser context
6840 * @nargs: the number of arguments
6841 *
6842 * Implement the number() XPath function
6843 * number number(object?)
6844 */
6845void
6846xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6847 xmlXPathObjectPtr cur;
6848 double res;
6849
6850 if (nargs == 0) {
6851 if (ctxt->context->node == NULL) {
6852 valuePush(ctxt, xmlXPathNewFloat(0.0));
6853 } else {
6854 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6855
6856 res = xmlXPathStringEvalNumber(content);
6857 valuePush(ctxt, xmlXPathNewFloat(res));
6858 xmlFree(content);
6859 }
6860 return;
6861 }
6862
6863 CHECK_ARITY(1);
6864 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006865 cur = xmlXPathConvertNumber(cur);
6866 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006867}
6868
6869/**
6870 * xmlXPathSumFunction:
6871 * @ctxt: the XPath Parser context
6872 * @nargs: the number of arguments
6873 *
6874 * Implement the sum() XPath function
6875 * number sum(node-set)
6876 * The sum function returns the sum of the values of the nodes in
6877 * the argument node-set.
6878 */
6879void
6880xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6881 xmlXPathObjectPtr cur;
6882 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006883 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00006884
6885 CHECK_ARITY(1);
6886 if ((ctxt->value == NULL) ||
6887 ((ctxt->value->type != XPATH_NODESET) &&
6888 (ctxt->value->type != XPATH_XSLT_TREE)))
6889 XP_ERROR(XPATH_INVALID_TYPE);
6890 cur = valuePop(ctxt);
6891
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006892 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006893 valuePush(ctxt, xmlXPathNewFloat(0.0));
6894 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006895 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
6896 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006897 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006898 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00006899 }
6900 xmlXPathFreeObject(cur);
6901}
6902
6903/**
6904 * xmlXPathFloorFunction:
6905 * @ctxt: the XPath Parser context
6906 * @nargs: the number of arguments
6907 *
6908 * Implement the floor() XPath function
6909 * number floor(number)
6910 * The floor function returns the largest (closest to positive infinity)
6911 * number that is not greater than the argument and that is an integer.
6912 */
6913void
6914xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006915 double f;
6916
Owen Taylor3473f882001-02-23 17:55:21 +00006917 CHECK_ARITY(1);
6918 CAST_TO_NUMBER;
6919 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006920
6921 f = (double)((int) ctxt->value->floatval);
6922 if (f != ctxt->value->floatval) {
6923 if (ctxt->value->floatval > 0)
6924 ctxt->value->floatval = f;
6925 else
6926 ctxt->value->floatval = f - 1;
6927 }
Owen Taylor3473f882001-02-23 17:55:21 +00006928}
6929
6930/**
6931 * xmlXPathCeilingFunction:
6932 * @ctxt: the XPath Parser context
6933 * @nargs: the number of arguments
6934 *
6935 * Implement the ceiling() XPath function
6936 * number ceiling(number)
6937 * The ceiling function returns the smallest (closest to negative infinity)
6938 * number that is not less than the argument and that is an integer.
6939 */
6940void
6941xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6942 double f;
6943
6944 CHECK_ARITY(1);
6945 CAST_TO_NUMBER;
6946 CHECK_TYPE(XPATH_NUMBER);
6947
6948#if 0
6949 ctxt->value->floatval = ceil(ctxt->value->floatval);
6950#else
6951 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006952 if (f != ctxt->value->floatval) {
6953 if (ctxt->value->floatval > 0)
6954 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00006955 else {
6956 if (ctxt->value->floatval < 0 && f == 0)
6957 ctxt->value->floatval = xmlXPathNZERO;
6958 else
6959 ctxt->value->floatval = f;
6960 }
6961
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006962 }
Owen Taylor3473f882001-02-23 17:55:21 +00006963#endif
6964}
6965
6966/**
6967 * xmlXPathRoundFunction:
6968 * @ctxt: the XPath Parser context
6969 * @nargs: the number of arguments
6970 *
6971 * Implement the round() XPath function
6972 * number round(number)
6973 * The round function returns the number that is closest to the
6974 * argument and that is an integer. If there are two such numbers,
6975 * then the one that is even is returned.
6976 */
6977void
6978xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6979 double f;
6980
6981 CHECK_ARITY(1);
6982 CAST_TO_NUMBER;
6983 CHECK_TYPE(XPATH_NUMBER);
6984
Daniel Veillardcda96922001-08-21 10:56:31 +00006985 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
6986 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
6987 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00006988 (ctxt->value->floatval == 0.0))
6989 return;
6990
Owen Taylor3473f882001-02-23 17:55:21 +00006991 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006992 if (ctxt->value->floatval < 0) {
6993 if (ctxt->value->floatval < f - 0.5)
6994 ctxt->value->floatval = f - 1;
6995 else
6996 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00006997 if (ctxt->value->floatval == 0)
6998 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006999 } else {
7000 if (ctxt->value->floatval < f + 0.5)
7001 ctxt->value->floatval = f;
7002 else
7003 ctxt->value->floatval = f + 1;
7004 }
Owen Taylor3473f882001-02-23 17:55:21 +00007005}
7006
7007/************************************************************************
7008 * *
7009 * The Parser *
7010 * *
7011 ************************************************************************/
7012
7013/*
7014 * a couple of forward declarations since we use a recursive call based
7015 * implementation.
7016 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007017static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007018static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007019static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007020static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00007021static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
7022 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00007023
7024/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00007025 * xmlXPathCurrentChar:
7026 * @ctxt: the XPath parser context
7027 * @cur: pointer to the beginning of the char
7028 * @len: pointer to the length of the char read
7029 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007030 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00007031 * bytes in the input buffer.
7032 *
Daniel Veillard60087f32001-10-10 09:45:09 +00007033 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00007034 */
7035
7036static int
7037xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
7038 unsigned char c;
7039 unsigned int val;
7040 const xmlChar *cur;
7041
7042 if (ctxt == NULL)
7043 return(0);
7044 cur = ctxt->cur;
7045
7046 /*
7047 * We are supposed to handle UTF8, check it's valid
7048 * From rfc2044: encoding of the Unicode values on UTF-8:
7049 *
7050 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
7051 * 0000 0000-0000 007F 0xxxxxxx
7052 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
7053 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
7054 *
7055 * Check for the 0x110000 limit too
7056 */
7057 c = *cur;
7058 if (c & 0x80) {
7059 if ((cur[1] & 0xc0) != 0x80)
7060 goto encoding_error;
7061 if ((c & 0xe0) == 0xe0) {
7062
7063 if ((cur[2] & 0xc0) != 0x80)
7064 goto encoding_error;
7065 if ((c & 0xf0) == 0xf0) {
7066 if (((c & 0xf8) != 0xf0) ||
7067 ((cur[3] & 0xc0) != 0x80))
7068 goto encoding_error;
7069 /* 4-byte code */
7070 *len = 4;
7071 val = (cur[0] & 0x7) << 18;
7072 val |= (cur[1] & 0x3f) << 12;
7073 val |= (cur[2] & 0x3f) << 6;
7074 val |= cur[3] & 0x3f;
7075 } else {
7076 /* 3-byte code */
7077 *len = 3;
7078 val = (cur[0] & 0xf) << 12;
7079 val |= (cur[1] & 0x3f) << 6;
7080 val |= cur[2] & 0x3f;
7081 }
7082 } else {
7083 /* 2-byte code */
7084 *len = 2;
7085 val = (cur[0] & 0x1f) << 6;
7086 val |= cur[1] & 0x3f;
7087 }
7088 if (!IS_CHAR(val)) {
7089 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
7090 }
7091 return(val);
7092 } else {
7093 /* 1-byte code */
7094 *len = 1;
7095 return((int) *cur);
7096 }
7097encoding_error:
7098 /*
7099 * If we detect an UTF8 error that probably mean that the
7100 * input encoding didn't get properly advertized in the
7101 * declaration header. Report the error and switch the encoding
7102 * to ISO-Latin-1 (if you don't like this policy, just declare the
7103 * encoding !)
7104 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00007105 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00007106 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007107}
7108
7109/**
Owen Taylor3473f882001-02-23 17:55:21 +00007110 * xmlXPathParseNCName:
7111 * @ctxt: the XPath Parser context
7112 *
7113 * parse an XML namespace non qualified name.
7114 *
7115 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7116 *
7117 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7118 * CombiningChar | Extender
7119 *
7120 * Returns the namespace name or NULL
7121 */
7122
7123xmlChar *
7124xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00007125 const xmlChar *in;
7126 xmlChar *ret;
7127 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007128
Daniel Veillard2156a562001-04-28 12:24:34 +00007129 /*
7130 * Accelerator for simple ASCII names
7131 */
7132 in = ctxt->cur;
7133 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7134 ((*in >= 0x41) && (*in <= 0x5A)) ||
7135 (*in == '_')) {
7136 in++;
7137 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7138 ((*in >= 0x41) && (*in <= 0x5A)) ||
7139 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00007140 (*in == '_') || (*in == '.') ||
7141 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00007142 in++;
7143 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7144 (*in == '[') || (*in == ']') || (*in == ':') ||
7145 (*in == '@') || (*in == '*')) {
7146 count = in - ctxt->cur;
7147 if (count == 0)
7148 return(NULL);
7149 ret = xmlStrndup(ctxt->cur, count);
7150 ctxt->cur = in;
7151 return(ret);
7152 }
7153 }
7154 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00007155}
7156
Daniel Veillard2156a562001-04-28 12:24:34 +00007157
Owen Taylor3473f882001-02-23 17:55:21 +00007158/**
7159 * xmlXPathParseQName:
7160 * @ctxt: the XPath Parser context
7161 * @prefix: a xmlChar **
7162 *
7163 * parse an XML qualified name
7164 *
7165 * [NS 5] QName ::= (Prefix ':')? LocalPart
7166 *
7167 * [NS 6] Prefix ::= NCName
7168 *
7169 * [NS 7] LocalPart ::= NCName
7170 *
7171 * Returns the function returns the local part, and prefix is updated
7172 * to get the Prefix if any.
7173 */
7174
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007175static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007176xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7177 xmlChar *ret = NULL;
7178
7179 *prefix = NULL;
7180 ret = xmlXPathParseNCName(ctxt);
7181 if (CUR == ':') {
7182 *prefix = ret;
7183 NEXT;
7184 ret = xmlXPathParseNCName(ctxt);
7185 }
7186 return(ret);
7187}
7188
7189/**
7190 * xmlXPathParseName:
7191 * @ctxt: the XPath Parser context
7192 *
7193 * parse an XML name
7194 *
7195 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7196 * CombiningChar | Extender
7197 *
7198 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7199 *
7200 * Returns the namespace name or NULL
7201 */
7202
7203xmlChar *
7204xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007205 const xmlChar *in;
7206 xmlChar *ret;
7207 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007208
Daniel Veillard61d80a22001-04-27 17:13:01 +00007209 /*
7210 * Accelerator for simple ASCII names
7211 */
7212 in = ctxt->cur;
7213 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7214 ((*in >= 0x41) && (*in <= 0x5A)) ||
7215 (*in == '_') || (*in == ':')) {
7216 in++;
7217 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7218 ((*in >= 0x41) && (*in <= 0x5A)) ||
7219 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00007220 (*in == '_') || (*in == '-') ||
7221 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00007222 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007223 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007224 count = in - ctxt->cur;
7225 ret = xmlStrndup(ctxt->cur, count);
7226 ctxt->cur = in;
7227 return(ret);
7228 }
7229 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007230 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00007231}
7232
Daniel Veillard61d80a22001-04-27 17:13:01 +00007233static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00007234xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007235 xmlChar buf[XML_MAX_NAMELEN + 5];
7236 int len = 0, l;
7237 int c;
7238
7239 /*
7240 * Handler for more complex cases
7241 */
7242 c = CUR_CHAR(l);
7243 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00007244 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7245 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00007246 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00007247 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007248 return(NULL);
7249 }
7250
7251 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7252 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7253 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007254 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007255 (IS_COMBINING(c)) ||
7256 (IS_EXTENDER(c)))) {
7257 COPY_BUF(l,buf,len,c);
7258 NEXTL(l);
7259 c = CUR_CHAR(l);
7260 if (len >= XML_MAX_NAMELEN) {
7261 /*
7262 * Okay someone managed to make a huge name, so he's ready to pay
7263 * for the processing speed.
7264 */
7265 xmlChar *buffer;
7266 int max = len * 2;
7267
7268 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
7269 if (buffer == NULL) {
7270 XP_ERROR0(XPATH_MEMORY_ERROR);
7271 }
7272 memcpy(buffer, buf, len);
7273 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7274 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007275 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007276 (IS_COMBINING(c)) ||
7277 (IS_EXTENDER(c))) {
7278 if (len + 10 > max) {
7279 max *= 2;
7280 buffer = (xmlChar *) xmlRealloc(buffer,
7281 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007282 if (buffer == NULL) {
7283 XP_ERROR0(XPATH_MEMORY_ERROR);
7284 }
7285 }
7286 COPY_BUF(l,buffer,len,c);
7287 NEXTL(l);
7288 c = CUR_CHAR(l);
7289 }
7290 buffer[len] = 0;
7291 return(buffer);
7292 }
7293 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007294 if (len == 0)
7295 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007296 return(xmlStrndup(buf, len));
7297}
Daniel Veillard3cd72402002-05-13 10:33:30 +00007298
7299#define MAX_FRAC 20
7300
7301static double my_pow10[MAX_FRAC] = {
7302 1.0, 10.0, 100.0, 1000.0, 10000.0,
7303 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7304 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7305 100000000000000.0,
7306 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
7307 1000000000000000000.0, 10000000000000000000.0
7308};
7309
Owen Taylor3473f882001-02-23 17:55:21 +00007310/**
7311 * xmlXPathStringEvalNumber:
7312 * @str: A string to scan
7313 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00007314 * [30a] Float ::= Number ('e' Digits?)?
7315 *
Owen Taylor3473f882001-02-23 17:55:21 +00007316 * [30] Number ::= Digits ('.' Digits?)?
7317 * | '.' Digits
7318 * [31] Digits ::= [0-9]+
7319 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007320 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00007321 * In complement of the Number expression, this function also handles
7322 * negative values : '-' Number.
7323 *
7324 * Returns the double value.
7325 */
7326double
7327xmlXPathStringEvalNumber(const xmlChar *str) {
7328 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00007329 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007330 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007331 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007332 int exponent = 0;
7333 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007334#ifdef __GNUC__
7335 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007336 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007337#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00007338 if (cur == NULL) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00007339 while (IS_BLANK(*cur)) cur++;
7340 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7341 return(xmlXPathNAN);
7342 }
7343 if (*cur == '-') {
7344 isneg = 1;
7345 cur++;
7346 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007347
7348#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007349 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007350 * tmp/temp is a workaround against a gcc compiler bug
7351 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007352 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007353 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007354 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007355 ret = ret * 10;
7356 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00007357 ok = 1;
7358 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00007359 temp = (double) tmp;
7360 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007361 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007362#else
Daniel Veillard7b416132002-03-07 08:36:03 +00007363 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007364 while ((*cur >= '0') && (*cur <= '9')) {
7365 ret = ret * 10 + (*cur - '0');
7366 ok = 1;
7367 cur++;
7368 }
7369#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007370
Owen Taylor3473f882001-02-23 17:55:21 +00007371 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007372 int v, frac = 0;
7373 double fraction = 0;
7374
Owen Taylor3473f882001-02-23 17:55:21 +00007375 cur++;
7376 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7377 return(xmlXPathNAN);
7378 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007379 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
7380 v = (*cur - '0');
7381 fraction = fraction * 10 + v;
7382 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007383 cur++;
7384 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007385 fraction /= my_pow10[frac];
7386 ret = ret + fraction;
7387 while ((*cur >= '0') && (*cur <= '9'))
7388 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007389 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007390 if ((*cur == 'e') || (*cur == 'E')) {
7391 cur++;
7392 if (*cur == '-') {
7393 is_exponent_negative = 1;
7394 cur++;
7395 }
7396 while ((*cur >= '0') && (*cur <= '9')) {
7397 exponent = exponent * 10 + (*cur - '0');
7398 cur++;
7399 }
7400 }
Owen Taylor3473f882001-02-23 17:55:21 +00007401 while (IS_BLANK(*cur)) cur++;
7402 if (*cur != 0) return(xmlXPathNAN);
7403 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007404 if (is_exponent_negative) exponent = -exponent;
7405 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007406 return(ret);
7407}
7408
7409/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007410 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007411 * @ctxt: the XPath Parser context
7412 *
7413 * [30] Number ::= Digits ('.' Digits?)?
7414 * | '.' Digits
7415 * [31] Digits ::= [0-9]+
7416 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007417 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007418 *
7419 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007420static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007421xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7422{
Owen Taylor3473f882001-02-23 17:55:21 +00007423 double ret = 0.0;
7424 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007425 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007426 int exponent = 0;
7427 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007428#ifdef __GNUC__
7429 unsigned long tmp = 0;
7430 double temp;
7431#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007432
7433 CHECK_ERROR;
7434 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7435 XP_ERROR(XPATH_NUMBER_ERROR);
7436 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007437#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007438 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007439 * tmp/temp is a workaround against a gcc compiler bug
7440 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007441 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007442 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007443 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007444 ret = ret * 10;
7445 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007446 ok = 1;
7447 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007448 temp = (double) tmp;
7449 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007450 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007451#else
7452 ret = 0;
7453 while ((CUR >= '0') && (CUR <= '9')) {
7454 ret = ret * 10 + (CUR - '0');
7455 ok = 1;
7456 NEXT;
7457 }
7458#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007459 if (CUR == '.') {
7460 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007461 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7462 XP_ERROR(XPATH_NUMBER_ERROR);
7463 }
7464 while ((CUR >= '0') && (CUR <= '9')) {
7465 mult /= 10;
7466 ret = ret + (CUR - '0') * mult;
7467 NEXT;
7468 }
Owen Taylor3473f882001-02-23 17:55:21 +00007469 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007470 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007471 NEXT;
7472 if (CUR == '-') {
7473 is_exponent_negative = 1;
7474 NEXT;
7475 }
7476 while ((CUR >= '0') && (CUR <= '9')) {
7477 exponent = exponent * 10 + (CUR - '0');
7478 NEXT;
7479 }
7480 if (is_exponent_negative)
7481 exponent = -exponent;
7482 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007483 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007484 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007485 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007486}
7487
7488/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007489 * xmlXPathParseLiteral:
7490 * @ctxt: the XPath Parser context
7491 *
7492 * Parse a Literal
7493 *
7494 * [29] Literal ::= '"' [^"]* '"'
7495 * | "'" [^']* "'"
7496 *
7497 * Returns the value found or NULL in case of error
7498 */
7499static xmlChar *
7500xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7501 const xmlChar *q;
7502 xmlChar *ret = NULL;
7503
7504 if (CUR == '"') {
7505 NEXT;
7506 q = CUR_PTR;
7507 while ((IS_CHAR(CUR)) && (CUR != '"'))
7508 NEXT;
7509 if (!IS_CHAR(CUR)) {
7510 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7511 } else {
7512 ret = xmlStrndup(q, CUR_PTR - q);
7513 NEXT;
7514 }
7515 } else if (CUR == '\'') {
7516 NEXT;
7517 q = CUR_PTR;
7518 while ((IS_CHAR(CUR)) && (CUR != '\''))
7519 NEXT;
7520 if (!IS_CHAR(CUR)) {
7521 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7522 } else {
7523 ret = xmlStrndup(q, CUR_PTR - q);
7524 NEXT;
7525 }
7526 } else {
7527 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7528 }
7529 return(ret);
7530}
7531
7532/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007533 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007534 * @ctxt: the XPath Parser context
7535 *
7536 * Parse a Literal and push it on the stack.
7537 *
7538 * [29] Literal ::= '"' [^"]* '"'
7539 * | "'" [^']* "'"
7540 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007541 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007542 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007543static void
7544xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007545 const xmlChar *q;
7546 xmlChar *ret = NULL;
7547
7548 if (CUR == '"') {
7549 NEXT;
7550 q = CUR_PTR;
7551 while ((IS_CHAR(CUR)) && (CUR != '"'))
7552 NEXT;
7553 if (!IS_CHAR(CUR)) {
7554 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7555 } else {
7556 ret = xmlStrndup(q, CUR_PTR - q);
7557 NEXT;
7558 }
7559 } else if (CUR == '\'') {
7560 NEXT;
7561 q = CUR_PTR;
7562 while ((IS_CHAR(CUR)) && (CUR != '\''))
7563 NEXT;
7564 if (!IS_CHAR(CUR)) {
7565 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7566 } else {
7567 ret = xmlStrndup(q, CUR_PTR - q);
7568 NEXT;
7569 }
7570 } else {
7571 XP_ERROR(XPATH_START_LITERAL_ERROR);
7572 }
7573 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007574 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7575 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007576 xmlFree(ret);
7577}
7578
7579/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007580 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007581 * @ctxt: the XPath Parser context
7582 *
7583 * Parse a VariableReference, evaluate it and push it on the stack.
7584 *
7585 * The variable bindings consist of a mapping from variable names
7586 * to variable values. The value of a variable is an object, which
7587 * of any of the types that are possible for the value of an expression,
7588 * and may also be of additional types not specified here.
7589 *
7590 * Early evaluation is possible since:
7591 * The variable bindings [...] used to evaluate a subexpression are
7592 * always the same as those used to evaluate the containing expression.
7593 *
7594 * [36] VariableReference ::= '$' QName
7595 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007596static void
7597xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007598 xmlChar *name;
7599 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007600
7601 SKIP_BLANKS;
7602 if (CUR != '$') {
7603 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7604 }
7605 NEXT;
7606 name = xmlXPathParseQName(ctxt, &prefix);
7607 if (name == NULL) {
7608 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7609 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007610 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007611 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7612 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007613 SKIP_BLANKS;
7614}
7615
7616/**
7617 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +00007618 * @name: a name string
7619 *
7620 * Is the name given a NodeType one.
7621 *
7622 * [38] NodeType ::= 'comment'
7623 * | 'text'
7624 * | 'processing-instruction'
7625 * | 'node'
7626 *
7627 * Returns 1 if true 0 otherwise
7628 */
7629int
7630xmlXPathIsNodeType(const xmlChar *name) {
7631 if (name == NULL)
7632 return(0);
7633
Daniel Veillard1971ee22002-01-31 20:29:19 +00007634 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007635 return(1);
7636 if (xmlStrEqual(name, BAD_CAST "text"))
7637 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007638 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007639 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007640 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007641 return(1);
7642 return(0);
7643}
7644
7645/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007646 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007647 * @ctxt: the XPath Parser context
7648 *
7649 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7650 * [17] Argument ::= Expr
7651 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007652 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007653 * pushed on the stack
7654 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007655static void
7656xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007657 xmlChar *name;
7658 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007659 int nbargs = 0;
7660
7661 name = xmlXPathParseQName(ctxt, &prefix);
7662 if (name == NULL) {
7663 XP_ERROR(XPATH_EXPR_ERROR);
7664 }
7665 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007666#ifdef DEBUG_EXPR
7667 if (prefix == NULL)
7668 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7669 name);
7670 else
7671 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7672 prefix, name);
7673#endif
7674
Owen Taylor3473f882001-02-23 17:55:21 +00007675 if (CUR != '(') {
7676 XP_ERROR(XPATH_EXPR_ERROR);
7677 }
7678 NEXT;
7679 SKIP_BLANKS;
7680
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007681 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +00007682 if (CUR != ')') {
7683 while (CUR != 0) {
7684 int op1 = ctxt->comp->last;
7685 ctxt->comp->last = -1;
7686 xmlXPathCompileExpr(ctxt);
7687 CHECK_ERROR;
7688 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
7689 nbargs++;
7690 if (CUR == ')') break;
7691 if (CUR != ',') {
7692 XP_ERROR(XPATH_EXPR_ERROR);
7693 }
7694 NEXT;
7695 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007696 }
Owen Taylor3473f882001-02-23 17:55:21 +00007697 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007698 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7699 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007700 NEXT;
7701 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007702}
7703
7704/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007705 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007706 * @ctxt: the XPath Parser context
7707 *
7708 * [15] PrimaryExpr ::= VariableReference
7709 * | '(' Expr ')'
7710 * | Literal
7711 * | Number
7712 * | FunctionCall
7713 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007714 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007715 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007716static void
7717xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007718 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007719 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007720 else if (CUR == '(') {
7721 NEXT;
7722 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007723 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007724 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00007725 if (CUR != ')') {
7726 XP_ERROR(XPATH_EXPR_ERROR);
7727 }
7728 NEXT;
7729 SKIP_BLANKS;
Daniel Veillard01917aa2002-04-10 11:30:41 +00007730 } else if (IS_DIGIT(CUR) || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007731 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007732 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007733 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007734 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007735 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007736 }
7737 SKIP_BLANKS;
7738}
7739
7740/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007741 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007742 * @ctxt: the XPath Parser context
7743 *
7744 * [20] FilterExpr ::= PrimaryExpr
7745 * | FilterExpr Predicate
7746 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007747 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007748 * Square brackets are used to filter expressions in the same way that
7749 * they are used in location paths. It is an error if the expression to
7750 * be filtered does not evaluate to a node-set. The context node list
7751 * used for evaluating the expression in square brackets is the node-set
7752 * to be filtered listed in document order.
7753 */
7754
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007755static void
7756xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
7757 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007758 CHECK_ERROR;
7759 SKIP_BLANKS;
7760
7761 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007762 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00007763 SKIP_BLANKS;
7764 }
7765
7766
7767}
7768
7769/**
7770 * xmlXPathScanName:
7771 * @ctxt: the XPath Parser context
7772 *
7773 * Trickery: parse an XML name but without consuming the input flow
7774 * Needed to avoid insanity in the parser state.
7775 *
7776 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7777 * CombiningChar | Extender
7778 *
7779 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7780 *
7781 * [6] Names ::= Name (S Name)*
7782 *
7783 * Returns the Name parsed or NULL
7784 */
7785
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007786static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007787xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7788 xmlChar buf[XML_MAX_NAMELEN];
7789 int len = 0;
7790
7791 SKIP_BLANKS;
7792 if (!IS_LETTER(CUR) && (CUR != '_') &&
7793 (CUR != ':')) {
7794 return(NULL);
7795 }
7796
7797 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7798 (NXT(len) == '.') || (NXT(len) == '-') ||
7799 (NXT(len) == '_') || (NXT(len) == ':') ||
7800 (IS_COMBINING(NXT(len))) ||
7801 (IS_EXTENDER(NXT(len)))) {
7802 buf[len] = NXT(len);
7803 len++;
7804 if (len >= XML_MAX_NAMELEN) {
7805 xmlGenericError(xmlGenericErrorContext,
7806 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
7807 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7808 (NXT(len) == '.') || (NXT(len) == '-') ||
7809 (NXT(len) == '_') || (NXT(len) == ':') ||
7810 (IS_COMBINING(NXT(len))) ||
7811 (IS_EXTENDER(NXT(len))))
7812 len++;
7813 break;
7814 }
7815 }
7816 return(xmlStrndup(buf, len));
7817}
7818
7819/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007820 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007821 * @ctxt: the XPath Parser context
7822 *
7823 * [19] PathExpr ::= LocationPath
7824 * | FilterExpr
7825 * | FilterExpr '/' RelativeLocationPath
7826 * | FilterExpr '//' RelativeLocationPath
7827 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007828 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007829 * The / operator and // operators combine an arbitrary expression
7830 * and a relative location path. It is an error if the expression
7831 * does not evaluate to a node-set.
7832 * The / operator does composition in the same way as when / is
7833 * used in a location path. As in location paths, // is short for
7834 * /descendant-or-self::node()/.
7835 */
7836
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007837static void
7838xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007839 int lc = 1; /* Should we branch to LocationPath ? */
7840 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7841
7842 SKIP_BLANKS;
7843 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
Daniel Veillard01917aa2002-04-10 11:30:41 +00007844 (CUR == '\'') || (CUR == '"') || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00007845 lc = 0;
7846 } else if (CUR == '*') {
7847 /* relative or absolute location path */
7848 lc = 1;
7849 } else if (CUR == '/') {
7850 /* relative or absolute location path */
7851 lc = 1;
7852 } else if (CUR == '@') {
7853 /* relative abbreviated attribute location path */
7854 lc = 1;
7855 } else if (CUR == '.') {
7856 /* relative abbreviated attribute location path */
7857 lc = 1;
7858 } else {
7859 /*
7860 * Problem is finding if we have a name here whether it's:
7861 * - a nodetype
7862 * - a function call in which case it's followed by '('
7863 * - an axis in which case it's followed by ':'
7864 * - a element name
7865 * We do an a priori analysis here rather than having to
7866 * maintain parsed token content through the recursive function
7867 * calls. This looks uglier but makes the code quite easier to
7868 * read/write/debug.
7869 */
7870 SKIP_BLANKS;
7871 name = xmlXPathScanName(ctxt);
7872 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7873#ifdef DEBUG_STEP
7874 xmlGenericError(xmlGenericErrorContext,
7875 "PathExpr: Axis\n");
7876#endif
7877 lc = 1;
7878 xmlFree(name);
7879 } else if (name != NULL) {
7880 int len =xmlStrlen(name);
7881 int blank = 0;
7882
7883
7884 while (NXT(len) != 0) {
7885 if (NXT(len) == '/') {
7886 /* element name */
7887#ifdef DEBUG_STEP
7888 xmlGenericError(xmlGenericErrorContext,
7889 "PathExpr: AbbrRelLocation\n");
7890#endif
7891 lc = 1;
7892 break;
7893 } else if (IS_BLANK(NXT(len))) {
7894 /* skip to next */
7895 blank = 1;
7896 } else if (NXT(len) == ':') {
7897#ifdef DEBUG_STEP
7898 xmlGenericError(xmlGenericErrorContext,
7899 "PathExpr: AbbrRelLocation\n");
7900#endif
7901 lc = 1;
7902 break;
7903 } else if ((NXT(len) == '(')) {
7904 /* Note Type or Function */
7905 if (xmlXPathIsNodeType(name)) {
7906#ifdef DEBUG_STEP
7907 xmlGenericError(xmlGenericErrorContext,
7908 "PathExpr: Type search\n");
7909#endif
7910 lc = 1;
7911 } else {
7912#ifdef DEBUG_STEP
7913 xmlGenericError(xmlGenericErrorContext,
7914 "PathExpr: function call\n");
7915#endif
7916 lc = 0;
7917 }
7918 break;
7919 } else if ((NXT(len) == '[')) {
7920 /* element name */
7921#ifdef DEBUG_STEP
7922 xmlGenericError(xmlGenericErrorContext,
7923 "PathExpr: AbbrRelLocation\n");
7924#endif
7925 lc = 1;
7926 break;
7927 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
7928 (NXT(len) == '=')) {
7929 lc = 1;
7930 break;
7931 } else {
7932 lc = 1;
7933 break;
7934 }
7935 len++;
7936 }
7937 if (NXT(len) == 0) {
7938#ifdef DEBUG_STEP
7939 xmlGenericError(xmlGenericErrorContext,
7940 "PathExpr: AbbrRelLocation\n");
7941#endif
7942 /* element name */
7943 lc = 1;
7944 }
7945 xmlFree(name);
7946 } else {
7947 /* make sure all cases are covered explicitely */
7948 XP_ERROR(XPATH_EXPR_ERROR);
7949 }
7950 }
7951
7952 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007953 if (CUR == '/') {
7954 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
7955 } else {
7956 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007957 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007958 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007959 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007960 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007961 CHECK_ERROR;
7962 if ((CUR == '/') && (NXT(1) == '/')) {
7963 SKIP(2);
7964 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007965
7966 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7967 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
7968 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
7969
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007970 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007971 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007972 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007973 }
7974 }
7975 SKIP_BLANKS;
7976}
7977
7978/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007979 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007980 * @ctxt: the XPath Parser context
7981 *
7982 * [18] UnionExpr ::= PathExpr
7983 * | UnionExpr '|' PathExpr
7984 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007985 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007986 */
7987
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007988static void
7989xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
7990 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007991 CHECK_ERROR;
7992 SKIP_BLANKS;
7993 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007994 int op1 = ctxt->comp->last;
7995 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007996
7997 NEXT;
7998 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007999 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008000
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008001 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8002
Owen Taylor3473f882001-02-23 17:55:21 +00008003 SKIP_BLANKS;
8004 }
Owen Taylor3473f882001-02-23 17:55:21 +00008005}
8006
8007/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008008 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008009 * @ctxt: the XPath Parser context
8010 *
8011 * [27] UnaryExpr ::= UnionExpr
8012 * | '-' UnaryExpr
8013 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008014 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008015 */
8016
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008017static void
8018xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008019 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008020 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008021
8022 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00008023 while (CUR == '-') {
8024 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008025 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008026 NEXT;
8027 SKIP_BLANKS;
8028 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008029
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008030 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008031 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008032 if (found) {
8033 if (minus)
8034 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8035 else
8036 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008037 }
8038}
8039
8040/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008041 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008042 * @ctxt: the XPath Parser context
8043 *
8044 * [26] MultiplicativeExpr ::= UnaryExpr
8045 * | MultiplicativeExpr MultiplyOperator UnaryExpr
8046 * | MultiplicativeExpr 'div' UnaryExpr
8047 * | MultiplicativeExpr 'mod' UnaryExpr
8048 * [34] MultiplyOperator ::= '*'
8049 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008050 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008051 */
8052
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008053static void
8054xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8055 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008056 CHECK_ERROR;
8057 SKIP_BLANKS;
8058 while ((CUR == '*') ||
8059 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8060 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8061 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008062 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008063
8064 if (CUR == '*') {
8065 op = 0;
8066 NEXT;
8067 } else if (CUR == 'd') {
8068 op = 1;
8069 SKIP(3);
8070 } else if (CUR == 'm') {
8071 op = 2;
8072 SKIP(3);
8073 }
8074 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008075 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008076 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008077 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008078 SKIP_BLANKS;
8079 }
8080}
8081
8082/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008083 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008084 * @ctxt: the XPath Parser context
8085 *
8086 * [25] AdditiveExpr ::= MultiplicativeExpr
8087 * | AdditiveExpr '+' MultiplicativeExpr
8088 * | AdditiveExpr '-' MultiplicativeExpr
8089 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008090 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008091 */
8092
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008093static void
8094xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008095
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008096 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008097 CHECK_ERROR;
8098 SKIP_BLANKS;
8099 while ((CUR == '+') || (CUR == '-')) {
8100 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008101 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008102
8103 if (CUR == '+') plus = 1;
8104 else plus = 0;
8105 NEXT;
8106 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008107 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008108 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008109 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008110 SKIP_BLANKS;
8111 }
8112}
8113
8114/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008115 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008116 * @ctxt: the XPath Parser context
8117 *
8118 * [24] RelationalExpr ::= AdditiveExpr
8119 * | RelationalExpr '<' AdditiveExpr
8120 * | RelationalExpr '>' AdditiveExpr
8121 * | RelationalExpr '<=' AdditiveExpr
8122 * | RelationalExpr '>=' AdditiveExpr
8123 *
8124 * A <= B > C is allowed ? Answer from James, yes with
8125 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8126 * which is basically what got implemented.
8127 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008128 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00008129 * on the stack
8130 */
8131
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008132static void
8133xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8134 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008135 CHECK_ERROR;
8136 SKIP_BLANKS;
8137 while ((CUR == '<') ||
8138 (CUR == '>') ||
8139 ((CUR == '<') && (NXT(1) == '=')) ||
8140 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008141 int inf, strict;
8142 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008143
8144 if (CUR == '<') inf = 1;
8145 else inf = 0;
8146 if (NXT(1) == '=') strict = 0;
8147 else strict = 1;
8148 NEXT;
8149 if (!strict) NEXT;
8150 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008151 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008152 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008153 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00008154 SKIP_BLANKS;
8155 }
8156}
8157
8158/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008159 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008160 * @ctxt: the XPath Parser context
8161 *
8162 * [23] EqualityExpr ::= RelationalExpr
8163 * | EqualityExpr '=' RelationalExpr
8164 * | EqualityExpr '!=' RelationalExpr
8165 *
8166 * A != B != C is allowed ? Answer from James, yes with
8167 * (RelationalExpr = RelationalExpr) = RelationalExpr
8168 * (RelationalExpr != RelationalExpr) != RelationalExpr
8169 * which is basically what got implemented.
8170 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008171 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008172 *
8173 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008174static void
8175xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8176 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008177 CHECK_ERROR;
8178 SKIP_BLANKS;
8179 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008180 int eq;
8181 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008182
8183 if (CUR == '=') eq = 1;
8184 else eq = 0;
8185 NEXT;
8186 if (!eq) NEXT;
8187 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008188 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008189 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008190 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008191 SKIP_BLANKS;
8192 }
8193}
8194
8195/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008196 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008197 * @ctxt: the XPath Parser context
8198 *
8199 * [22] AndExpr ::= EqualityExpr
8200 * | AndExpr 'and' EqualityExpr
8201 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008202 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008203 *
8204 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008205static void
8206xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8207 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008208 CHECK_ERROR;
8209 SKIP_BLANKS;
8210 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008211 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008212 SKIP(3);
8213 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008214 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008215 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008216 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008217 SKIP_BLANKS;
8218 }
8219}
8220
8221/**
Daniel Veillard591b4be2003-02-09 23:33:36 +00008222 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008223 * @ctxt: the XPath Parser context
8224 *
8225 * [14] Expr ::= OrExpr
8226 * [21] OrExpr ::= AndExpr
8227 * | OrExpr 'or' AndExpr
8228 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008229 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00008230 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008231static void
8232xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8233 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008234 CHECK_ERROR;
8235 SKIP_BLANKS;
8236 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008237 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008238 SKIP(2);
8239 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008240 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008241 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008242 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8243 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00008244 SKIP_BLANKS;
8245 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008246 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8247 /* more ops could be optimized too */
8248 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8249 }
Owen Taylor3473f882001-02-23 17:55:21 +00008250}
8251
8252/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008253 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00008254 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008255 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00008256 *
8257 * [8] Predicate ::= '[' PredicateExpr ']'
8258 * [9] PredicateExpr ::= Expr
8259 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008260 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008261 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008262static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008263xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008264 int op1 = ctxt->comp->last;
8265
8266 SKIP_BLANKS;
8267 if (CUR != '[') {
8268 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8269 }
8270 NEXT;
8271 SKIP_BLANKS;
8272
8273 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008274 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008275 CHECK_ERROR;
8276
8277 if (CUR != ']') {
8278 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8279 }
8280
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008281 if (filter)
8282 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8283 else
8284 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008285
8286 NEXT;
8287 SKIP_BLANKS;
8288}
8289
8290/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008291 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00008292 * @ctxt: the XPath Parser context
8293 * @test: pointer to a xmlXPathTestVal
8294 * @type: pointer to a xmlXPathTypeVal
8295 * @prefix: placeholder for a possible name prefix
8296 *
8297 * [7] NodeTest ::= NameTest
8298 * | NodeType '(' ')'
8299 * | 'processing-instruction' '(' Literal ')'
8300 *
8301 * [37] NameTest ::= '*'
8302 * | NCName ':' '*'
8303 * | QName
8304 * [38] NodeType ::= 'comment'
8305 * | 'text'
8306 * | 'processing-instruction'
8307 * | 'node'
8308 *
8309 * Returns the name found and update @test, @type and @prefix appropriately
8310 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008311static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008312xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8313 xmlXPathTypeVal *type, const xmlChar **prefix,
8314 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008315 int blanks;
8316
8317 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8318 STRANGE;
8319 return(NULL);
8320 }
8321 *type = 0;
8322 *test = 0;
8323 *prefix = NULL;
8324 SKIP_BLANKS;
8325
8326 if ((name == NULL) && (CUR == '*')) {
8327 /*
8328 * All elements
8329 */
8330 NEXT;
8331 *test = NODE_TEST_ALL;
8332 return(NULL);
8333 }
8334
8335 if (name == NULL)
8336 name = xmlXPathParseNCName(ctxt);
8337 if (name == NULL) {
8338 XP_ERROR0(XPATH_EXPR_ERROR);
8339 }
8340
8341 blanks = IS_BLANK(CUR);
8342 SKIP_BLANKS;
8343 if (CUR == '(') {
8344 NEXT;
8345 /*
8346 * NodeType or PI search
8347 */
8348 if (xmlStrEqual(name, BAD_CAST "comment"))
8349 *type = NODE_TYPE_COMMENT;
8350 else if (xmlStrEqual(name, BAD_CAST "node"))
8351 *type = NODE_TYPE_NODE;
8352 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8353 *type = NODE_TYPE_PI;
8354 else if (xmlStrEqual(name, BAD_CAST "text"))
8355 *type = NODE_TYPE_TEXT;
8356 else {
8357 if (name != NULL)
8358 xmlFree(name);
8359 XP_ERROR0(XPATH_EXPR_ERROR);
8360 }
8361
8362 *test = NODE_TEST_TYPE;
8363
8364 SKIP_BLANKS;
8365 if (*type == NODE_TYPE_PI) {
8366 /*
8367 * Specific case: search a PI by name.
8368 */
Owen Taylor3473f882001-02-23 17:55:21 +00008369 if (name != NULL)
8370 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008371 name = NULL;
8372 if (CUR != ')') {
8373 name = xmlXPathParseLiteral(ctxt);
8374 CHECK_ERROR 0;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00008375 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00008376 SKIP_BLANKS;
8377 }
Owen Taylor3473f882001-02-23 17:55:21 +00008378 }
8379 if (CUR != ')') {
8380 if (name != NULL)
8381 xmlFree(name);
8382 XP_ERROR0(XPATH_UNCLOSED_ERROR);
8383 }
8384 NEXT;
8385 return(name);
8386 }
8387 *test = NODE_TEST_NAME;
8388 if ((!blanks) && (CUR == ':')) {
8389 NEXT;
8390
8391 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008392 * Since currently the parser context don't have a
8393 * namespace list associated:
8394 * The namespace name for this prefix can be computed
8395 * only at evaluation time. The compilation is done
8396 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008397 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008398#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008399 *prefix = xmlXPathNsLookup(ctxt->context, name);
8400 if (name != NULL)
8401 xmlFree(name);
8402 if (*prefix == NULL) {
8403 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8404 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008405#else
8406 *prefix = name;
8407#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008408
8409 if (CUR == '*') {
8410 /*
8411 * All elements
8412 */
8413 NEXT;
8414 *test = NODE_TEST_ALL;
8415 return(NULL);
8416 }
8417
8418 name = xmlXPathParseNCName(ctxt);
8419 if (name == NULL) {
8420 XP_ERROR0(XPATH_EXPR_ERROR);
8421 }
8422 }
8423 return(name);
8424}
8425
8426/**
8427 * xmlXPathIsAxisName:
8428 * @name: a preparsed name token
8429 *
8430 * [6] AxisName ::= 'ancestor'
8431 * | 'ancestor-or-self'
8432 * | 'attribute'
8433 * | 'child'
8434 * | 'descendant'
8435 * | 'descendant-or-self'
8436 * | 'following'
8437 * | 'following-sibling'
8438 * | 'namespace'
8439 * | 'parent'
8440 * | 'preceding'
8441 * | 'preceding-sibling'
8442 * | 'self'
8443 *
8444 * Returns the axis or 0
8445 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008446static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008447xmlXPathIsAxisName(const xmlChar *name) {
8448 xmlXPathAxisVal ret = 0;
8449 switch (name[0]) {
8450 case 'a':
8451 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8452 ret = AXIS_ANCESTOR;
8453 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8454 ret = AXIS_ANCESTOR_OR_SELF;
8455 if (xmlStrEqual(name, BAD_CAST "attribute"))
8456 ret = AXIS_ATTRIBUTE;
8457 break;
8458 case 'c':
8459 if (xmlStrEqual(name, BAD_CAST "child"))
8460 ret = AXIS_CHILD;
8461 break;
8462 case 'd':
8463 if (xmlStrEqual(name, BAD_CAST "descendant"))
8464 ret = AXIS_DESCENDANT;
8465 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8466 ret = AXIS_DESCENDANT_OR_SELF;
8467 break;
8468 case 'f':
8469 if (xmlStrEqual(name, BAD_CAST "following"))
8470 ret = AXIS_FOLLOWING;
8471 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8472 ret = AXIS_FOLLOWING_SIBLING;
8473 break;
8474 case 'n':
8475 if (xmlStrEqual(name, BAD_CAST "namespace"))
8476 ret = AXIS_NAMESPACE;
8477 break;
8478 case 'p':
8479 if (xmlStrEqual(name, BAD_CAST "parent"))
8480 ret = AXIS_PARENT;
8481 if (xmlStrEqual(name, BAD_CAST "preceding"))
8482 ret = AXIS_PRECEDING;
8483 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8484 ret = AXIS_PRECEDING_SIBLING;
8485 break;
8486 case 's':
8487 if (xmlStrEqual(name, BAD_CAST "self"))
8488 ret = AXIS_SELF;
8489 break;
8490 }
8491 return(ret);
8492}
8493
8494/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008495 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008496 * @ctxt: the XPath Parser context
8497 *
8498 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8499 * | AbbreviatedStep
8500 *
8501 * [12] AbbreviatedStep ::= '.' | '..'
8502 *
8503 * [5] AxisSpecifier ::= AxisName '::'
8504 * | AbbreviatedAxisSpecifier
8505 *
8506 * [13] AbbreviatedAxisSpecifier ::= '@'?
8507 *
8508 * Modified for XPtr range support as:
8509 *
8510 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8511 * | AbbreviatedStep
8512 * | 'range-to' '(' Expr ')' Predicate*
8513 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008514 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008515 * A location step of . is short for self::node(). This is
8516 * particularly useful in conjunction with //. For example, the
8517 * location path .//para is short for
8518 * self::node()/descendant-or-self::node()/child::para
8519 * and so will select all para descendant elements of the context
8520 * node.
8521 * Similarly, a location step of .. is short for parent::node().
8522 * For example, ../title is short for parent::node()/child::title
8523 * and so will select the title children of the parent of the context
8524 * node.
8525 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008526static void
8527xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008528#ifdef LIBXML_XPTR_ENABLED
8529 int rangeto = 0;
8530 int op2 = -1;
8531#endif
8532
Owen Taylor3473f882001-02-23 17:55:21 +00008533 SKIP_BLANKS;
8534 if ((CUR == '.') && (NXT(1) == '.')) {
8535 SKIP(2);
8536 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008537 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8538 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008539 } else if (CUR == '.') {
8540 NEXT;
8541 SKIP_BLANKS;
8542 } else {
8543 xmlChar *name = NULL;
8544 const xmlChar *prefix = NULL;
8545 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008546 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008547 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008548 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008549
8550 /*
8551 * The modification needed for XPointer change to the production
8552 */
8553#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008554 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008555 name = xmlXPathParseNCName(ctxt);
8556 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008557 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008558 xmlFree(name);
8559 SKIP_BLANKS;
8560 if (CUR != '(') {
8561 XP_ERROR(XPATH_EXPR_ERROR);
8562 }
8563 NEXT;
8564 SKIP_BLANKS;
8565
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008566 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008567 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008568 CHECK_ERROR;
8569
8570 SKIP_BLANKS;
8571 if (CUR != ')') {
8572 XP_ERROR(XPATH_EXPR_ERROR);
8573 }
8574 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008575 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008576 goto eval_predicates;
8577 }
8578 }
8579#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008580 if (CUR == '*') {
8581 axis = AXIS_CHILD;
8582 } else {
8583 if (name == NULL)
8584 name = xmlXPathParseNCName(ctxt);
8585 if (name != NULL) {
8586 axis = xmlXPathIsAxisName(name);
8587 if (axis != 0) {
8588 SKIP_BLANKS;
8589 if ((CUR == ':') && (NXT(1) == ':')) {
8590 SKIP(2);
8591 xmlFree(name);
8592 name = NULL;
8593 } else {
8594 /* an element name can conflict with an axis one :-\ */
8595 axis = AXIS_CHILD;
8596 }
Owen Taylor3473f882001-02-23 17:55:21 +00008597 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008598 axis = AXIS_CHILD;
8599 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008600 } else if (CUR == '@') {
8601 NEXT;
8602 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008603 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008604 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008605 }
Owen Taylor3473f882001-02-23 17:55:21 +00008606 }
8607
8608 CHECK_ERROR;
8609
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008610 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008611 if (test == 0)
8612 return;
8613
8614#ifdef DEBUG_STEP
8615 xmlGenericError(xmlGenericErrorContext,
8616 "Basis : computing new set\n");
8617#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008618
Owen Taylor3473f882001-02-23 17:55:21 +00008619#ifdef DEBUG_STEP
8620 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008621 if (ctxt->value == NULL)
8622 xmlGenericError(xmlGenericErrorContext, "no value\n");
8623 else if (ctxt->value->nodesetval == NULL)
8624 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8625 else
8626 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008627#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008628
8629eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008630 op1 = ctxt->comp->last;
8631 ctxt->comp->last = -1;
8632
Owen Taylor3473f882001-02-23 17:55:21 +00008633 SKIP_BLANKS;
8634 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008635 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008636 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008637
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008638#ifdef LIBXML_XPTR_ENABLED
8639 if (rangeto) {
8640 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8641 } else
8642#endif
8643 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8644 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008645
Owen Taylor3473f882001-02-23 17:55:21 +00008646 }
8647#ifdef DEBUG_STEP
8648 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008649 if (ctxt->value == NULL)
8650 xmlGenericError(xmlGenericErrorContext, "no value\n");
8651 else if (ctxt->value->nodesetval == NULL)
8652 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8653 else
8654 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8655 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008656#endif
8657}
8658
8659/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008660 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008661 * @ctxt: the XPath Parser context
8662 *
8663 * [3] RelativeLocationPath ::= Step
8664 * | RelativeLocationPath '/' Step
8665 * | AbbreviatedRelativeLocationPath
8666 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8667 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008668 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008669 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008670static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008671xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008672(xmlXPathParserContextPtr ctxt) {
8673 SKIP_BLANKS;
8674 if ((CUR == '/') && (NXT(1) == '/')) {
8675 SKIP(2);
8676 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008677 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8678 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008679 } else if (CUR == '/') {
8680 NEXT;
8681 SKIP_BLANKS;
8682 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008683 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008684 SKIP_BLANKS;
8685 while (CUR == '/') {
8686 if ((CUR == '/') && (NXT(1) == '/')) {
8687 SKIP(2);
8688 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008689 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008690 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008691 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008692 } else if (CUR == '/') {
8693 NEXT;
8694 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008695 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008696 }
8697 SKIP_BLANKS;
8698 }
8699}
8700
8701/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008702 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008703 * @ctxt: the XPath Parser context
8704 *
8705 * [1] LocationPath ::= RelativeLocationPath
8706 * | AbsoluteLocationPath
8707 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8708 * | AbbreviatedAbsoluteLocationPath
8709 * [10] AbbreviatedAbsoluteLocationPath ::=
8710 * '//' RelativeLocationPath
8711 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008712 * Compile a location path
8713 *
Owen Taylor3473f882001-02-23 17:55:21 +00008714 * // is short for /descendant-or-self::node()/. For example,
8715 * //para is short for /descendant-or-self::node()/child::para and
8716 * so will select any para element in the document (even a para element
8717 * that is a document element will be selected by //para since the
8718 * document element node is a child of the root node); div//para is
8719 * short for div/descendant-or-self::node()/child::para and so will
8720 * select all para descendants of div children.
8721 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008722static void
8723xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008724 SKIP_BLANKS;
8725 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008726 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008727 } else {
8728 while (CUR == '/') {
8729 if ((CUR == '/') && (NXT(1) == '/')) {
8730 SKIP(2);
8731 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008732 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8733 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008734 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008735 } else if (CUR == '/') {
8736 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008737 SKIP_BLANKS;
8738 if ((CUR != 0 ) &&
8739 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
8740 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008741 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008742 }
8743 }
8744 }
8745}
8746
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008747/************************************************************************
8748 * *
8749 * XPath precompiled expression evaluation *
8750 * *
8751 ************************************************************************/
8752
Daniel Veillardf06307e2001-07-03 10:35:50 +00008753static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008754xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8755
8756/**
8757 * xmlXPathNodeCollectAndTest:
8758 * @ctxt: the XPath Parser context
8759 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008760 * @first: pointer to the first element in document order
8761 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008762 *
8763 * This is the function implementing a step: based on the current list
8764 * of nodes, it builds up a new list, looking at all nodes under that
8765 * axis and selecting them it also do the predicate filtering
8766 *
8767 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00008768 *
8769 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008770 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008771static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008772xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008773 xmlXPathStepOpPtr op,
8774 xmlNodePtr * first, xmlNodePtr * last)
8775{
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008776 xmlXPathAxisVal axis = op->value;
8777 xmlXPathTestVal test = op->value2;
8778 xmlXPathTypeVal type = op->value3;
8779 const xmlChar *prefix = op->value4;
8780 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008781 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008782
8783#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008784 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008785#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008786 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008787 xmlNodeSetPtr ret, list;
8788 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008789 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00008790 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008791 xmlNodePtr cur = NULL;
8792 xmlXPathObjectPtr obj;
8793 xmlNodeSetPtr nodelist;
8794 xmlNodePtr tmp;
8795
Daniel Veillardf06307e2001-07-03 10:35:50 +00008796 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008797 obj = valuePop(ctxt);
8798 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00008799 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008800 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008801 URI = xmlXPathNsLookup(ctxt->context, prefix);
8802 if (URI == NULL)
8803 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008804 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008805#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008806 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008807#endif
8808 switch (axis) {
8809 case AXIS_ANCESTOR:
8810#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008811 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008812#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008813 first = NULL;
8814 next = xmlXPathNextAncestor;
8815 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008816 case AXIS_ANCESTOR_OR_SELF:
8817#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008818 xmlGenericError(xmlGenericErrorContext,
8819 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008820#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008821 first = NULL;
8822 next = xmlXPathNextAncestorOrSelf;
8823 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008824 case AXIS_ATTRIBUTE:
8825#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008826 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008827#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008828 first = NULL;
8829 last = NULL;
8830 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00008831 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008832 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008833 case AXIS_CHILD:
8834#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008835 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008836#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008837 last = NULL;
8838 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00008839 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008840 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008841 case AXIS_DESCENDANT:
8842#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008843 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008844#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008845 last = NULL;
8846 next = xmlXPathNextDescendant;
8847 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008848 case AXIS_DESCENDANT_OR_SELF:
8849#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008850 xmlGenericError(xmlGenericErrorContext,
8851 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008852#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008853 last = NULL;
8854 next = xmlXPathNextDescendantOrSelf;
8855 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008856 case AXIS_FOLLOWING:
8857#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008858 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008859#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008860 last = NULL;
8861 next = xmlXPathNextFollowing;
8862 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008863 case AXIS_FOLLOWING_SIBLING:
8864#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008865 xmlGenericError(xmlGenericErrorContext,
8866 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008867#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008868 last = NULL;
8869 next = xmlXPathNextFollowingSibling;
8870 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008871 case AXIS_NAMESPACE:
8872#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008873 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008874#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008875 first = NULL;
8876 last = NULL;
8877 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00008878 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008879 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008880 case AXIS_PARENT:
8881#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008882 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008883#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008884 first = NULL;
8885 next = xmlXPathNextParent;
8886 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008887 case AXIS_PRECEDING:
8888#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008889 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008890#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008891 first = NULL;
8892 next = xmlXPathNextPrecedingInternal;
8893 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008894 case AXIS_PRECEDING_SIBLING:
8895#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008896 xmlGenericError(xmlGenericErrorContext,
8897 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008898#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008899 first = NULL;
8900 next = xmlXPathNextPrecedingSibling;
8901 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008902 case AXIS_SELF:
8903#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008904 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008905#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008906 first = NULL;
8907 last = NULL;
8908 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00008909 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008910 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008911 }
8912 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008913 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008914
8915 nodelist = obj->nodesetval;
8916 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008917 xmlXPathFreeObject(obj);
8918 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8919 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008920 }
8921 addNode = xmlXPathNodeSetAddUnique;
8922 ret = NULL;
8923#ifdef DEBUG_STEP
8924 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008925 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008926 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008927 case NODE_TEST_NONE:
8928 xmlGenericError(xmlGenericErrorContext,
8929 " searching for none !!!\n");
8930 break;
8931 case NODE_TEST_TYPE:
8932 xmlGenericError(xmlGenericErrorContext,
8933 " searching for type %d\n", type);
8934 break;
8935 case NODE_TEST_PI:
8936 xmlGenericError(xmlGenericErrorContext,
8937 " searching for PI !!!\n");
8938 break;
8939 case NODE_TEST_ALL:
8940 xmlGenericError(xmlGenericErrorContext,
8941 " searching for *\n");
8942 break;
8943 case NODE_TEST_NS:
8944 xmlGenericError(xmlGenericErrorContext,
8945 " searching for namespace %s\n",
8946 prefix);
8947 break;
8948 case NODE_TEST_NAME:
8949 xmlGenericError(xmlGenericErrorContext,
8950 " searching for name %s\n", name);
8951 if (prefix != NULL)
8952 xmlGenericError(xmlGenericErrorContext,
8953 " with namespace %s\n", prefix);
8954 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008955 }
8956 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8957#endif
8958 /*
8959 * 2.3 Node Tests
8960 * - For the attribute axis, the principal node type is attribute.
8961 * - For the namespace axis, the principal node type is namespace.
8962 * - For other axes, the principal node type is element.
8963 *
8964 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008965 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008966 * select all element children of the context node
8967 */
8968 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008969 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008970 ctxt->context->node = nodelist->nodeTab[i];
8971
Daniel Veillardf06307e2001-07-03 10:35:50 +00008972 cur = NULL;
8973 list = xmlXPathNodeSetCreate(NULL);
8974 do {
8975 cur = next(ctxt, cur);
8976 if (cur == NULL)
8977 break;
8978 if ((first != NULL) && (*first == cur))
8979 break;
8980 if (((t % 256) == 0) &&
8981 (first != NULL) && (*first != NULL) &&
8982 (xmlXPathCmpNodes(*first, cur) >= 0))
8983 break;
8984 if ((last != NULL) && (*last == cur))
8985 break;
8986 if (((t % 256) == 0) &&
8987 (last != NULL) && (*last != NULL) &&
8988 (xmlXPathCmpNodes(cur, *last) >= 0))
8989 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008990 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008991#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008992 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
8993#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008994 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008995 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008996 ctxt->context->node = tmp;
8997 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008998 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008999 if ((cur->type == type) ||
9000 ((type == NODE_TYPE_NODE) &&
9001 ((cur->type == XML_DOCUMENT_NODE) ||
9002 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9003 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00009004 (cur->type == XML_NAMESPACE_DECL) ||
9005 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00009006 (cur->type == XML_PI_NODE) ||
9007 (cur->type == XML_COMMENT_NODE) ||
9008 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00009009 (cur->type == XML_TEXT_NODE))) ||
9010 ((type == NODE_TYPE_TEXT) &&
9011 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009012#ifdef DEBUG_STEP
9013 n++;
9014#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009015 addNode(list, cur);
9016 }
9017 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009018 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009019 if (cur->type == XML_PI_NODE) {
9020 if ((name != NULL) &&
9021 (!xmlStrEqual(name, cur->name)))
9022 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009023#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009024 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009025#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009026 addNode(list, cur);
9027 }
9028 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009029 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009030 if (axis == AXIS_ATTRIBUTE) {
9031 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009032#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009033 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009034#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009035 addNode(list, cur);
9036 }
9037 } else if (axis == AXIS_NAMESPACE) {
9038 if (cur->type == XML_NAMESPACE_DECL) {
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 Veillard044fc6b2002-03-04 17:09:44 +00009042 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9043 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009044 }
9045 } else {
9046 if (cur->type == XML_ELEMENT_NODE) {
9047 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009048#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009049 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009050#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009051 addNode(list, cur);
9052 } else if ((cur->ns != NULL) &&
9053 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009054#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009055 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009056#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009057 addNode(list, cur);
9058 }
9059 }
9060 }
9061 break;
9062 case NODE_TEST_NS:{
9063 TODO;
9064 break;
9065 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009066 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009067 switch (cur->type) {
9068 case XML_ELEMENT_NODE:
9069 if (xmlStrEqual(name, cur->name)) {
9070 if (prefix == NULL) {
9071 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009072#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009073 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009074#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009075 addNode(list, cur);
9076 }
9077 } else {
9078 if ((cur->ns != NULL) &&
9079 (xmlStrEqual(URI,
9080 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009081#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009082 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009083#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009084 addNode(list, cur);
9085 }
9086 }
9087 }
9088 break;
9089 case XML_ATTRIBUTE_NODE:{
9090 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009091
Daniel Veillardf06307e2001-07-03 10:35:50 +00009092 if (xmlStrEqual(name, attr->name)) {
9093 if (prefix == NULL) {
9094 if ((attr->ns == NULL) ||
9095 (attr->ns->prefix == NULL)) {
9096#ifdef DEBUG_STEP
9097 n++;
9098#endif
9099 addNode(list,
9100 (xmlNodePtr) attr);
9101 }
9102 } else {
9103 if ((attr->ns != NULL) &&
9104 (xmlStrEqual(URI,
9105 attr->ns->
9106 href))) {
9107#ifdef DEBUG_STEP
9108 n++;
9109#endif
9110 addNode(list,
9111 (xmlNodePtr) attr);
9112 }
9113 }
9114 }
9115 break;
9116 }
9117 case XML_NAMESPACE_DECL:
9118 if (cur->type == XML_NAMESPACE_DECL) {
9119 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009120
Daniel Veillardf06307e2001-07-03 10:35:50 +00009121 if ((ns->prefix != NULL) && (name != NULL)
9122 && (xmlStrEqual(ns->prefix, name))) {
9123#ifdef DEBUG_STEP
9124 n++;
9125#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009126 xmlXPathNodeSetAddNs(list,
9127 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009128 }
9129 }
9130 break;
9131 default:
9132 break;
9133 }
9134 break;
9135 break;
9136 }
9137 } while (cur != NULL);
9138
9139 /*
9140 * If there is some predicate filtering do it now
9141 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009142 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009143 xmlXPathObjectPtr obj2;
9144
9145 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9146 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9147 CHECK_TYPE0(XPATH_NODESET);
9148 obj2 = valuePop(ctxt);
9149 list = obj2->nodesetval;
9150 obj2->nodesetval = NULL;
9151 xmlXPathFreeObject(obj2);
9152 }
9153 if (ret == NULL) {
9154 ret = list;
9155 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009156 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009157 xmlXPathFreeNodeSet(list);
9158 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009159 }
9160 ctxt->context->node = tmp;
9161#ifdef DEBUG_STEP
9162 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009163 "\nExamined %d nodes, found %d nodes at that step\n",
9164 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009165#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009166 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009167 if ((obj->boolval) && (obj->user != NULL)) {
9168 ctxt->value->boolval = 1;
9169 ctxt->value->user = obj->user;
9170 obj->user = NULL;
9171 obj->boolval = 0;
9172 }
9173 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009174 return(t);
9175}
9176
9177/**
9178 * xmlXPathNodeCollectAndTestNth:
9179 * @ctxt: the XPath Parser context
9180 * @op: the XPath precompiled step operation
9181 * @indx: the index to collect
9182 * @first: pointer to the first element in document order
9183 * @last: pointer to the last element in document order
9184 *
9185 * This is the function implementing a step: based on the current list
9186 * of nodes, it builds up a new list, looking at all nodes under that
9187 * axis and selecting them it also do the predicate filtering
9188 *
9189 * Pushes the new NodeSet resulting from the search.
9190 * Returns the number of node traversed
9191 */
9192static int
9193xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9194 xmlXPathStepOpPtr op, int indx,
9195 xmlNodePtr * first, xmlNodePtr * last)
9196{
9197 xmlXPathAxisVal axis = op->value;
9198 xmlXPathTestVal test = op->value2;
9199 xmlXPathTypeVal type = op->value3;
9200 const xmlChar *prefix = op->value4;
9201 const xmlChar *name = op->value5;
9202 const xmlChar *URI = NULL;
9203 int n = 0, t = 0;
9204
9205 int i;
9206 xmlNodeSetPtr list;
9207 xmlXPathTraversalFunction next = NULL;
9208 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9209 xmlNodePtr cur = NULL;
9210 xmlXPathObjectPtr obj;
9211 xmlNodeSetPtr nodelist;
9212 xmlNodePtr tmp;
9213
9214 CHECK_TYPE0(XPATH_NODESET);
9215 obj = valuePop(ctxt);
9216 addNode = xmlXPathNodeSetAdd;
9217 if (prefix != NULL) {
9218 URI = xmlXPathNsLookup(ctxt->context, prefix);
9219 if (URI == NULL)
9220 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9221 }
9222#ifdef DEBUG_STEP_NTH
9223 xmlGenericError(xmlGenericErrorContext, "new step : ");
9224 if (first != NULL) {
9225 if (*first != NULL)
9226 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9227 (*first)->name);
9228 else
9229 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9230 }
9231 if (last != NULL) {
9232 if (*last != NULL)
9233 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9234 (*last)->name);
9235 else
9236 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9237 }
9238#endif
9239 switch (axis) {
9240 case AXIS_ANCESTOR:
9241#ifdef DEBUG_STEP_NTH
9242 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9243#endif
9244 first = NULL;
9245 next = xmlXPathNextAncestor;
9246 break;
9247 case AXIS_ANCESTOR_OR_SELF:
9248#ifdef DEBUG_STEP_NTH
9249 xmlGenericError(xmlGenericErrorContext,
9250 "axis 'ancestors-or-self' ");
9251#endif
9252 first = NULL;
9253 next = xmlXPathNextAncestorOrSelf;
9254 break;
9255 case AXIS_ATTRIBUTE:
9256#ifdef DEBUG_STEP_NTH
9257 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9258#endif
9259 first = NULL;
9260 last = NULL;
9261 next = xmlXPathNextAttribute;
9262 break;
9263 case AXIS_CHILD:
9264#ifdef DEBUG_STEP_NTH
9265 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9266#endif
9267 last = NULL;
9268 next = xmlXPathNextChild;
9269 break;
9270 case AXIS_DESCENDANT:
9271#ifdef DEBUG_STEP_NTH
9272 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9273#endif
9274 last = NULL;
9275 next = xmlXPathNextDescendant;
9276 break;
9277 case AXIS_DESCENDANT_OR_SELF:
9278#ifdef DEBUG_STEP_NTH
9279 xmlGenericError(xmlGenericErrorContext,
9280 "axis 'descendant-or-self' ");
9281#endif
9282 last = NULL;
9283 next = xmlXPathNextDescendantOrSelf;
9284 break;
9285 case AXIS_FOLLOWING:
9286#ifdef DEBUG_STEP_NTH
9287 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9288#endif
9289 last = NULL;
9290 next = xmlXPathNextFollowing;
9291 break;
9292 case AXIS_FOLLOWING_SIBLING:
9293#ifdef DEBUG_STEP_NTH
9294 xmlGenericError(xmlGenericErrorContext,
9295 "axis 'following-siblings' ");
9296#endif
9297 last = NULL;
9298 next = xmlXPathNextFollowingSibling;
9299 break;
9300 case AXIS_NAMESPACE:
9301#ifdef DEBUG_STEP_NTH
9302 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9303#endif
9304 last = NULL;
9305 first = NULL;
9306 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9307 break;
9308 case AXIS_PARENT:
9309#ifdef DEBUG_STEP_NTH
9310 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9311#endif
9312 first = NULL;
9313 next = xmlXPathNextParent;
9314 break;
9315 case AXIS_PRECEDING:
9316#ifdef DEBUG_STEP_NTH
9317 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9318#endif
9319 first = NULL;
9320 next = xmlXPathNextPrecedingInternal;
9321 break;
9322 case AXIS_PRECEDING_SIBLING:
9323#ifdef DEBUG_STEP_NTH
9324 xmlGenericError(xmlGenericErrorContext,
9325 "axis 'preceding-sibling' ");
9326#endif
9327 first = NULL;
9328 next = xmlXPathNextPrecedingSibling;
9329 break;
9330 case AXIS_SELF:
9331#ifdef DEBUG_STEP_NTH
9332 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9333#endif
9334 first = NULL;
9335 last = NULL;
9336 next = xmlXPathNextSelf;
9337 break;
9338 }
9339 if (next == NULL)
9340 return(0);
9341
9342 nodelist = obj->nodesetval;
9343 if (nodelist == NULL) {
9344 xmlXPathFreeObject(obj);
9345 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9346 return(0);
9347 }
9348 addNode = xmlXPathNodeSetAddUnique;
9349#ifdef DEBUG_STEP_NTH
9350 xmlGenericError(xmlGenericErrorContext,
9351 " context contains %d nodes\n", nodelist->nodeNr);
9352 switch (test) {
9353 case NODE_TEST_NONE:
9354 xmlGenericError(xmlGenericErrorContext,
9355 " searching for none !!!\n");
9356 break;
9357 case NODE_TEST_TYPE:
9358 xmlGenericError(xmlGenericErrorContext,
9359 " searching for type %d\n", type);
9360 break;
9361 case NODE_TEST_PI:
9362 xmlGenericError(xmlGenericErrorContext,
9363 " searching for PI !!!\n");
9364 break;
9365 case NODE_TEST_ALL:
9366 xmlGenericError(xmlGenericErrorContext,
9367 " searching for *\n");
9368 break;
9369 case NODE_TEST_NS:
9370 xmlGenericError(xmlGenericErrorContext,
9371 " searching for namespace %s\n",
9372 prefix);
9373 break;
9374 case NODE_TEST_NAME:
9375 xmlGenericError(xmlGenericErrorContext,
9376 " searching for name %s\n", name);
9377 if (prefix != NULL)
9378 xmlGenericError(xmlGenericErrorContext,
9379 " with namespace %s\n", prefix);
9380 break;
9381 }
9382 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9383#endif
9384 /*
9385 * 2.3 Node Tests
9386 * - For the attribute axis, the principal node type is attribute.
9387 * - For the namespace axis, the principal node type is namespace.
9388 * - For other axes, the principal node type is element.
9389 *
9390 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009391 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009392 * select all element children of the context node
9393 */
9394 tmp = ctxt->context->node;
9395 list = xmlXPathNodeSetCreate(NULL);
9396 for (i = 0; i < nodelist->nodeNr; i++) {
9397 ctxt->context->node = nodelist->nodeTab[i];
9398
9399 cur = NULL;
9400 n = 0;
9401 do {
9402 cur = next(ctxt, cur);
9403 if (cur == NULL)
9404 break;
9405 if ((first != NULL) && (*first == cur))
9406 break;
9407 if (((t % 256) == 0) &&
9408 (first != NULL) && (*first != NULL) &&
9409 (xmlXPathCmpNodes(*first, cur) >= 0))
9410 break;
9411 if ((last != NULL) && (*last == cur))
9412 break;
9413 if (((t % 256) == 0) &&
9414 (last != NULL) && (*last != NULL) &&
9415 (xmlXPathCmpNodes(cur, *last) >= 0))
9416 break;
9417 t++;
9418 switch (test) {
9419 case NODE_TEST_NONE:
9420 ctxt->context->node = tmp;
9421 STRANGE return(0);
9422 case NODE_TEST_TYPE:
9423 if ((cur->type == type) ||
9424 ((type == NODE_TYPE_NODE) &&
9425 ((cur->type == XML_DOCUMENT_NODE) ||
9426 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9427 (cur->type == XML_ELEMENT_NODE) ||
9428 (cur->type == XML_PI_NODE) ||
9429 (cur->type == XML_COMMENT_NODE) ||
9430 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +00009431 (cur->type == XML_TEXT_NODE))) ||
9432 ((type == NODE_TYPE_TEXT) &&
9433 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009434 n++;
9435 if (n == indx)
9436 addNode(list, cur);
9437 }
9438 break;
9439 case NODE_TEST_PI:
9440 if (cur->type == XML_PI_NODE) {
9441 if ((name != NULL) &&
9442 (!xmlStrEqual(name, cur->name)))
9443 break;
9444 n++;
9445 if (n == indx)
9446 addNode(list, cur);
9447 }
9448 break;
9449 case NODE_TEST_ALL:
9450 if (axis == AXIS_ATTRIBUTE) {
9451 if (cur->type == XML_ATTRIBUTE_NODE) {
9452 n++;
9453 if (n == indx)
9454 addNode(list, cur);
9455 }
9456 } else if (axis == AXIS_NAMESPACE) {
9457 if (cur->type == XML_NAMESPACE_DECL) {
9458 n++;
9459 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009460 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9461 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009462 }
9463 } else {
9464 if (cur->type == XML_ELEMENT_NODE) {
9465 if (prefix == NULL) {
9466 n++;
9467 if (n == indx)
9468 addNode(list, cur);
9469 } else if ((cur->ns != NULL) &&
9470 (xmlStrEqual(URI, cur->ns->href))) {
9471 n++;
9472 if (n == indx)
9473 addNode(list, cur);
9474 }
9475 }
9476 }
9477 break;
9478 case NODE_TEST_NS:{
9479 TODO;
9480 break;
9481 }
9482 case NODE_TEST_NAME:
9483 switch (cur->type) {
9484 case XML_ELEMENT_NODE:
9485 if (xmlStrEqual(name, cur->name)) {
9486 if (prefix == NULL) {
9487 if (cur->ns == NULL) {
9488 n++;
9489 if (n == indx)
9490 addNode(list, cur);
9491 }
9492 } else {
9493 if ((cur->ns != NULL) &&
9494 (xmlStrEqual(URI,
9495 cur->ns->href))) {
9496 n++;
9497 if (n == indx)
9498 addNode(list, cur);
9499 }
9500 }
9501 }
9502 break;
9503 case XML_ATTRIBUTE_NODE:{
9504 xmlAttrPtr attr = (xmlAttrPtr) cur;
9505
9506 if (xmlStrEqual(name, attr->name)) {
9507 if (prefix == NULL) {
9508 if ((attr->ns == NULL) ||
9509 (attr->ns->prefix == NULL)) {
9510 n++;
9511 if (n == indx)
9512 addNode(list, cur);
9513 }
9514 } else {
9515 if ((attr->ns != NULL) &&
9516 (xmlStrEqual(URI,
9517 attr->ns->
9518 href))) {
9519 n++;
9520 if (n == indx)
9521 addNode(list, cur);
9522 }
9523 }
9524 }
9525 break;
9526 }
9527 case XML_NAMESPACE_DECL:
9528 if (cur->type == XML_NAMESPACE_DECL) {
9529 xmlNsPtr ns = (xmlNsPtr) cur;
9530
9531 if ((ns->prefix != NULL) && (name != NULL)
9532 && (xmlStrEqual(ns->prefix, name))) {
9533 n++;
9534 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009535 xmlXPathNodeSetAddNs(list,
9536 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009537 }
9538 }
9539 break;
9540 default:
9541 break;
9542 }
9543 break;
9544 break;
9545 }
9546 } while (n < indx);
9547 }
9548 ctxt->context->node = tmp;
9549#ifdef DEBUG_STEP_NTH
9550 xmlGenericError(xmlGenericErrorContext,
9551 "\nExamined %d nodes, found %d nodes at that step\n",
9552 t, list->nodeNr);
9553#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009554 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009555 if ((obj->boolval) && (obj->user != NULL)) {
9556 ctxt->value->boolval = 1;
9557 ctxt->value->user = obj->user;
9558 obj->user = NULL;
9559 obj->boolval = 0;
9560 }
9561 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009562 return(t);
9563}
9564
9565/**
9566 * xmlXPathCompOpEvalFirst:
9567 * @ctxt: the XPath parser context with the compiled expression
9568 * @op: an XPath compiled operation
9569 * @first: the first elem found so far
9570 *
9571 * Evaluate the Precompiled XPath operation searching only the first
9572 * element in document order
9573 *
9574 * Returns the number of examined objects.
9575 */
9576static int
9577xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9578 xmlXPathStepOpPtr op, xmlNodePtr * first)
9579{
9580 int total = 0, cur;
9581 xmlXPathCompExprPtr comp;
9582 xmlXPathObjectPtr arg1, arg2;
9583
Daniel Veillard556c6682001-10-06 09:59:51 +00009584 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009585 comp = ctxt->comp;
9586 switch (op->op) {
9587 case XPATH_OP_END:
9588 return (0);
9589 case XPATH_OP_UNION:
9590 total =
9591 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9592 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009593 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009594 if ((ctxt->value != NULL)
9595 && (ctxt->value->type == XPATH_NODESET)
9596 && (ctxt->value->nodesetval != NULL)
9597 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9598 /*
9599 * limit tree traversing to first node in the result
9600 */
9601 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9602 *first = ctxt->value->nodesetval->nodeTab[0];
9603 }
9604 cur =
9605 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9606 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009607 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009608 CHECK_TYPE0(XPATH_NODESET);
9609 arg2 = valuePop(ctxt);
9610
9611 CHECK_TYPE0(XPATH_NODESET);
9612 arg1 = valuePop(ctxt);
9613
9614 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9615 arg2->nodesetval);
9616 valuePush(ctxt, arg1);
9617 xmlXPathFreeObject(arg2);
9618 /* optimizer */
9619 if (total > cur)
9620 xmlXPathCompSwap(op);
9621 return (total + cur);
9622 case XPATH_OP_ROOT:
9623 xmlXPathRoot(ctxt);
9624 return (0);
9625 case XPATH_OP_NODE:
9626 if (op->ch1 != -1)
9627 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009628 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009629 if (op->ch2 != -1)
9630 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009631 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009632 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9633 return (total);
9634 case XPATH_OP_RESET:
9635 if (op->ch1 != -1)
9636 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009637 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009638 if (op->ch2 != -1)
9639 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009640 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009641 ctxt->context->node = NULL;
9642 return (total);
9643 case XPATH_OP_COLLECT:{
9644 if (op->ch1 == -1)
9645 return (total);
9646
9647 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009648 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009649
9650 /*
9651 * Optimization for [n] selection where n is a number
9652 */
9653 if ((op->ch2 != -1) &&
9654 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9655 (comp->steps[op->ch2].ch1 == -1) &&
9656 (comp->steps[op->ch2].ch2 != -1) &&
9657 (comp->steps[comp->steps[op->ch2].ch2].op ==
9658 XPATH_OP_VALUE)) {
9659 xmlXPathObjectPtr val;
9660
9661 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9662 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9663 int indx = (int) val->floatval;
9664
9665 if (val->floatval == (float) indx) {
9666 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9667 first, NULL);
9668 return (total);
9669 }
9670 }
9671 }
9672 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9673 return (total);
9674 }
9675 case XPATH_OP_VALUE:
9676 valuePush(ctxt,
9677 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9678 return (0);
9679 case XPATH_OP_SORT:
9680 if (op->ch1 != -1)
9681 total +=
9682 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9683 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009684 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009685 if ((ctxt->value != NULL)
9686 && (ctxt->value->type == XPATH_NODESET)
9687 && (ctxt->value->nodesetval != NULL))
9688 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9689 return (total);
9690 default:
9691 return (xmlXPathCompOpEval(ctxt, op));
9692 }
9693}
9694
9695/**
9696 * xmlXPathCompOpEvalLast:
9697 * @ctxt: the XPath parser context with the compiled expression
9698 * @op: an XPath compiled operation
9699 * @last: the last elem found so far
9700 *
9701 * Evaluate the Precompiled XPath operation searching only the last
9702 * element in document order
9703 *
9704 * Returns the number of node traversed
9705 */
9706static int
9707xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9708 xmlNodePtr * last)
9709{
9710 int total = 0, cur;
9711 xmlXPathCompExprPtr comp;
9712 xmlXPathObjectPtr arg1, arg2;
9713
Daniel Veillard556c6682001-10-06 09:59:51 +00009714 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009715 comp = ctxt->comp;
9716 switch (op->op) {
9717 case XPATH_OP_END:
9718 return (0);
9719 case XPATH_OP_UNION:
9720 total =
9721 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009722 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009723 if ((ctxt->value != NULL)
9724 && (ctxt->value->type == XPATH_NODESET)
9725 && (ctxt->value->nodesetval != NULL)
9726 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9727 /*
9728 * limit tree traversing to first node in the result
9729 */
9730 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9731 *last =
9732 ctxt->value->nodesetval->nodeTab[ctxt->value->
9733 nodesetval->nodeNr -
9734 1];
9735 }
9736 cur =
9737 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009738 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009739 if ((ctxt->value != NULL)
9740 && (ctxt->value->type == XPATH_NODESET)
9741 && (ctxt->value->nodesetval != NULL)
9742 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9743 }
9744 CHECK_TYPE0(XPATH_NODESET);
9745 arg2 = valuePop(ctxt);
9746
9747 CHECK_TYPE0(XPATH_NODESET);
9748 arg1 = valuePop(ctxt);
9749
9750 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9751 arg2->nodesetval);
9752 valuePush(ctxt, arg1);
9753 xmlXPathFreeObject(arg2);
9754 /* optimizer */
9755 if (total > cur)
9756 xmlXPathCompSwap(op);
9757 return (total + cur);
9758 case XPATH_OP_ROOT:
9759 xmlXPathRoot(ctxt);
9760 return (0);
9761 case XPATH_OP_NODE:
9762 if (op->ch1 != -1)
9763 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009764 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009765 if (op->ch2 != -1)
9766 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009767 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009768 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9769 return (total);
9770 case XPATH_OP_RESET:
9771 if (op->ch1 != -1)
9772 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009773 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009774 if (op->ch2 != -1)
9775 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009776 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009777 ctxt->context->node = NULL;
9778 return (total);
9779 case XPATH_OP_COLLECT:{
9780 if (op->ch1 == -1)
9781 return (0);
9782
9783 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009784 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009785
9786 /*
9787 * Optimization for [n] selection where n is a number
9788 */
9789 if ((op->ch2 != -1) &&
9790 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9791 (comp->steps[op->ch2].ch1 == -1) &&
9792 (comp->steps[op->ch2].ch2 != -1) &&
9793 (comp->steps[comp->steps[op->ch2].ch2].op ==
9794 XPATH_OP_VALUE)) {
9795 xmlXPathObjectPtr val;
9796
9797 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9798 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9799 int indx = (int) val->floatval;
9800
9801 if (val->floatval == (float) indx) {
9802 total +=
9803 xmlXPathNodeCollectAndTestNth(ctxt, op,
9804 indx, NULL,
9805 last);
9806 return (total);
9807 }
9808 }
9809 }
9810 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9811 return (total);
9812 }
9813 case XPATH_OP_VALUE:
9814 valuePush(ctxt,
9815 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9816 return (0);
9817 case XPATH_OP_SORT:
9818 if (op->ch1 != -1)
9819 total +=
9820 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9821 last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009822 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009823 if ((ctxt->value != NULL)
9824 && (ctxt->value->type == XPATH_NODESET)
9825 && (ctxt->value->nodesetval != NULL))
9826 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9827 return (total);
9828 default:
9829 return (xmlXPathCompOpEval(ctxt, op));
9830 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009831}
9832
Owen Taylor3473f882001-02-23 17:55:21 +00009833/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009834 * xmlXPathCompOpEval:
9835 * @ctxt: the XPath parser context with the compiled expression
9836 * @op: an XPath compiled operation
9837 *
9838 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009839 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009840 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009841static int
9842xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9843{
9844 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009845 int equal, ret;
9846 xmlXPathCompExprPtr comp;
9847 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009848 xmlNodePtr bak;
9849 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +00009850 int pp;
William M. Brack692092b2002-06-28 15:01:24 +00009851 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009852
Daniel Veillard556c6682001-10-06 09:59:51 +00009853 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009854 comp = ctxt->comp;
9855 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009856 case XPATH_OP_END:
9857 return (0);
9858 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009859 bakd = ctxt->context->doc;
9860 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009861 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009862 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009863 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009864 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009865 xmlXPathBooleanFunction(ctxt, 1);
9866 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9867 return (total);
9868 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009869 ctxt->context->doc = bakd;
9870 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009871 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009872 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009873 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009874 if (ctxt->error) {
9875 xmlXPathFreeObject(arg2);
9876 return(0);
9877 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009878 xmlXPathBooleanFunction(ctxt, 1);
9879 arg1 = valuePop(ctxt);
9880 arg1->boolval &= arg2->boolval;
9881 valuePush(ctxt, arg1);
9882 xmlXPathFreeObject(arg2);
9883 return (total);
9884 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009885 bakd = ctxt->context->doc;
9886 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009887 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009888 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009889 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009890 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009891 xmlXPathBooleanFunction(ctxt, 1);
9892 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9893 return (total);
9894 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009895 ctxt->context->doc = bakd;
9896 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009897 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009898 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009899 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009900 if (ctxt->error) {
9901 xmlXPathFreeObject(arg2);
9902 return(0);
9903 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009904 xmlXPathBooleanFunction(ctxt, 1);
9905 arg1 = valuePop(ctxt);
9906 arg1->boolval |= arg2->boolval;
9907 valuePush(ctxt, arg1);
9908 xmlXPathFreeObject(arg2);
9909 return (total);
9910 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009911 bakd = ctxt->context->doc;
9912 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009913 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009914 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009915 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009916 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009917 ctxt->context->doc = bakd;
9918 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009919 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009920 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009921 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009922 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +00009923 if (op->value)
9924 equal = xmlXPathEqualValues(ctxt);
9925 else
9926 equal = xmlXPathNotEqualValues(ctxt);
9927 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +00009928 return (total);
9929 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009930 bakd = ctxt->context->doc;
9931 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009932 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009933 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009934 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009935 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009936 ctxt->context->doc = bakd;
9937 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009938 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009939 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009940 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009941 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009942 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
9943 valuePush(ctxt, xmlXPathNewBoolean(ret));
9944 return (total);
9945 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009946 bakd = ctxt->context->doc;
9947 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009948 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009949 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009950 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009951 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009952 if (op->ch2 != -1) {
9953 ctxt->context->doc = bakd;
9954 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009955 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009956 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009957 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009958 }
Daniel Veillard556c6682001-10-06 09:59:51 +00009959 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009960 if (op->value == 0)
9961 xmlXPathSubValues(ctxt);
9962 else if (op->value == 1)
9963 xmlXPathAddValues(ctxt);
9964 else if (op->value == 2)
9965 xmlXPathValueFlipSign(ctxt);
9966 else if (op->value == 3) {
9967 CAST_TO_NUMBER;
9968 CHECK_TYPE0(XPATH_NUMBER);
9969 }
9970 return (total);
9971 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009972 bakd = ctxt->context->doc;
9973 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009974 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009975 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009976 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009977 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009978 ctxt->context->doc = bakd;
9979 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009980 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009981 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009982 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009983 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009984 if (op->value == 0)
9985 xmlXPathMultValues(ctxt);
9986 else if (op->value == 1)
9987 xmlXPathDivValues(ctxt);
9988 else if (op->value == 2)
9989 xmlXPathModValues(ctxt);
9990 return (total);
9991 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009992 bakd = ctxt->context->doc;
9993 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009994 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009995 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009996 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009997 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009998 ctxt->context->doc = bakd;
9999 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010000 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010001 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010002 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010003 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010004 CHECK_TYPE0(XPATH_NODESET);
10005 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010006
Daniel Veillardf06307e2001-07-03 10:35:50 +000010007 CHECK_TYPE0(XPATH_NODESET);
10008 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010009
Daniel Veillardf06307e2001-07-03 10:35:50 +000010010 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10011 arg2->nodesetval);
10012 valuePush(ctxt, arg1);
10013 xmlXPathFreeObject(arg2);
10014 return (total);
10015 case XPATH_OP_ROOT:
10016 xmlXPathRoot(ctxt);
10017 return (total);
10018 case XPATH_OP_NODE:
10019 if (op->ch1 != -1)
10020 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010021 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010022 if (op->ch2 != -1)
10023 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010024 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010025 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10026 return (total);
10027 case XPATH_OP_RESET:
10028 if (op->ch1 != -1)
10029 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010030 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010031 if (op->ch2 != -1)
10032 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010033 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010034 ctxt->context->node = NULL;
10035 return (total);
10036 case XPATH_OP_COLLECT:{
10037 if (op->ch1 == -1)
10038 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010039
Daniel Veillardf06307e2001-07-03 10:35:50 +000010040 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010041 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010042
Daniel Veillardf06307e2001-07-03 10:35:50 +000010043 /*
10044 * Optimization for [n] selection where n is a number
10045 */
10046 if ((op->ch2 != -1) &&
10047 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10048 (comp->steps[op->ch2].ch1 == -1) &&
10049 (comp->steps[op->ch2].ch2 != -1) &&
10050 (comp->steps[comp->steps[op->ch2].ch2].op ==
10051 XPATH_OP_VALUE)) {
10052 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +000010053
Daniel Veillardf06307e2001-07-03 10:35:50 +000010054 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10055 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10056 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010057
Daniel Veillardf06307e2001-07-03 10:35:50 +000010058 if (val->floatval == (float) indx) {
10059 total +=
10060 xmlXPathNodeCollectAndTestNth(ctxt, op,
10061 indx, NULL,
10062 NULL);
10063 return (total);
10064 }
10065 }
10066 }
10067 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
10068 return (total);
10069 }
10070 case XPATH_OP_VALUE:
10071 valuePush(ctxt,
10072 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10073 return (total);
10074 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000010075 xmlXPathObjectPtr val;
10076
Daniel Veillardf06307e2001-07-03 10:35:50 +000010077 if (op->ch1 != -1)
10078 total +=
10079 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010080 if (op->value5 == NULL) {
10081 val = xmlXPathVariableLookup(ctxt->context, op->value4);
10082 if (val == NULL) {
10083 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10084 return(0);
10085 }
10086 valuePush(ctxt, val);
10087 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010088 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010089
Daniel Veillardf06307e2001-07-03 10:35:50 +000010090 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10091 if (URI == NULL) {
10092 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010093 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010094 op->value4, op->value5);
10095 return (total);
10096 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010097 val = xmlXPathVariableLookupNS(ctxt->context,
10098 op->value4, URI);
10099 if (val == NULL) {
10100 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10101 return(0);
10102 }
10103 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010104 }
10105 return (total);
10106 }
10107 case XPATH_OP_FUNCTION:{
10108 xmlXPathFunction func;
10109 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000010110 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010111
10112 if (op->ch1 != -1)
10113 total +=
10114 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010115 if (ctxt->valueNr < op->value) {
10116 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010117 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010118 ctxt->error = XPATH_INVALID_OPERAND;
10119 return (total);
10120 }
10121 for (i = 0; i < op->value; i++)
10122 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10123 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010124 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010125 ctxt->error = XPATH_INVALID_OPERAND;
10126 return (total);
10127 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010128 if (op->cache != NULL)
10129 func = (xmlXPathFunction) op->cache;
10130 else {
10131 const xmlChar *URI = NULL;
10132
10133 if (op->value5 == NULL)
10134 func =
10135 xmlXPathFunctionLookup(ctxt->context,
10136 op->value4);
10137 else {
10138 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10139 if (URI == NULL) {
10140 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010141 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010142 op->value4, op->value5);
10143 return (total);
10144 }
10145 func = xmlXPathFunctionLookupNS(ctxt->context,
10146 op->value4, URI);
10147 }
10148 if (func == NULL) {
10149 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010150 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010151 op->value4);
10152 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010153 }
10154 op->cache = (void *) func;
10155 op->cacheURI = (void *) URI;
10156 }
10157 oldFunc = ctxt->context->function;
10158 oldFuncURI = ctxt->context->functionURI;
10159 ctxt->context->function = op->value4;
10160 ctxt->context->functionURI = op->cacheURI;
10161 func(ctxt, op->value);
10162 ctxt->context->function = oldFunc;
10163 ctxt->context->functionURI = oldFuncURI;
10164 return (total);
10165 }
10166 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000010167 bakd = ctxt->context->doc;
10168 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010169 if (op->ch1 != -1)
10170 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010171 ctxt->context->doc = bakd;
10172 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010173 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010174 if (op->ch2 != -1)
10175 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010176 ctxt->context->doc = bakd;
10177 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010178 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010179 return (total);
10180 case XPATH_OP_PREDICATE:
10181 case XPATH_OP_FILTER:{
10182 xmlXPathObjectPtr res;
10183 xmlXPathObjectPtr obj, tmp;
10184 xmlNodeSetPtr newset = NULL;
10185 xmlNodeSetPtr oldset;
10186 xmlNodePtr oldnode;
10187 int i;
10188
10189 /*
10190 * Optimization for ()[1] selection i.e. the first elem
10191 */
10192 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10193 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10194 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10195 xmlXPathObjectPtr val;
10196
10197 val = comp->steps[op->ch2].value4;
10198 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10199 (val->floatval == 1.0)) {
10200 xmlNodePtr first = NULL;
10201
10202 total +=
10203 xmlXPathCompOpEvalFirst(ctxt,
10204 &comp->steps[op->ch1],
10205 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010206 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010207 /*
10208 * The nodeset should be in document order,
10209 * Keep only the first value
10210 */
10211 if ((ctxt->value != NULL) &&
10212 (ctxt->value->type == XPATH_NODESET) &&
10213 (ctxt->value->nodesetval != NULL) &&
10214 (ctxt->value->nodesetval->nodeNr > 1))
10215 ctxt->value->nodesetval->nodeNr = 1;
10216 return (total);
10217 }
10218 }
10219 /*
10220 * Optimization for ()[last()] selection i.e. the last elem
10221 */
10222 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10223 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10224 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10225 int f = comp->steps[op->ch2].ch1;
10226
10227 if ((f != -1) &&
10228 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10229 (comp->steps[f].value5 == NULL) &&
10230 (comp->steps[f].value == 0) &&
10231 (comp->steps[f].value4 != NULL) &&
10232 (xmlStrEqual
10233 (comp->steps[f].value4, BAD_CAST "last"))) {
10234 xmlNodePtr last = NULL;
10235
10236 total +=
10237 xmlXPathCompOpEvalLast(ctxt,
10238 &comp->steps[op->ch1],
10239 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010240 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010241 /*
10242 * The nodeset should be in document order,
10243 * Keep only the last value
10244 */
10245 if ((ctxt->value != NULL) &&
10246 (ctxt->value->type == XPATH_NODESET) &&
10247 (ctxt->value->nodesetval != NULL) &&
10248 (ctxt->value->nodesetval->nodeTab != NULL) &&
10249 (ctxt->value->nodesetval->nodeNr > 1)) {
10250 ctxt->value->nodesetval->nodeTab[0] =
10251 ctxt->value->nodesetval->nodeTab[ctxt->
10252 value->
10253 nodesetval->
10254 nodeNr -
10255 1];
10256 ctxt->value->nodesetval->nodeNr = 1;
10257 }
10258 return (total);
10259 }
10260 }
10261
10262 if (op->ch1 != -1)
10263 total +=
10264 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010265 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010266 if (op->ch2 == -1)
10267 return (total);
10268 if (ctxt->value == NULL)
10269 return (total);
10270
10271 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010272
10273#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010274 /*
10275 * Hum are we filtering the result of an XPointer expression
10276 */
10277 if (ctxt->value->type == XPATH_LOCATIONSET) {
10278 xmlLocationSetPtr newlocset = NULL;
10279 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010280
Daniel Veillardf06307e2001-07-03 10:35:50 +000010281 /*
10282 * Extract the old locset, and then evaluate the result of the
10283 * expression for all the element in the locset. use it to grow
10284 * up a new locset.
10285 */
10286 CHECK_TYPE0(XPATH_LOCATIONSET);
10287 obj = valuePop(ctxt);
10288 oldlocset = obj->user;
10289 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010290
Daniel Veillardf06307e2001-07-03 10:35:50 +000010291 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10292 ctxt->context->contextSize = 0;
10293 ctxt->context->proximityPosition = 0;
10294 if (op->ch2 != -1)
10295 total +=
10296 xmlXPathCompOpEval(ctxt,
10297 &comp->steps[op->ch2]);
10298 res = valuePop(ctxt);
10299 if (res != NULL)
10300 xmlXPathFreeObject(res);
10301 valuePush(ctxt, obj);
10302 CHECK_ERROR0;
10303 return (total);
10304 }
10305 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010306
Daniel Veillardf06307e2001-07-03 10:35:50 +000010307 for (i = 0; i < oldlocset->locNr; i++) {
10308 /*
10309 * Run the evaluation with a node list made of a
10310 * single item in the nodelocset.
10311 */
10312 ctxt->context->node = oldlocset->locTab[i]->user;
10313 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10314 valuePush(ctxt, tmp);
10315 ctxt->context->contextSize = oldlocset->locNr;
10316 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010317
Daniel Veillardf06307e2001-07-03 10:35:50 +000010318 if (op->ch2 != -1)
10319 total +=
10320 xmlXPathCompOpEval(ctxt,
10321 &comp->steps[op->ch2]);
10322 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010323
Daniel Veillardf06307e2001-07-03 10:35:50 +000010324 /*
10325 * The result of the evaluation need to be tested to
10326 * decided whether the filter succeeded or not
10327 */
10328 res = valuePop(ctxt);
10329 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10330 xmlXPtrLocationSetAdd(newlocset,
10331 xmlXPathObjectCopy
10332 (oldlocset->locTab[i]));
10333 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010334
Daniel Veillardf06307e2001-07-03 10:35:50 +000010335 /*
10336 * Cleanup
10337 */
10338 if (res != NULL)
10339 xmlXPathFreeObject(res);
10340 if (ctxt->value == tmp) {
10341 res = valuePop(ctxt);
10342 xmlXPathFreeObject(res);
10343 }
10344
10345 ctxt->context->node = NULL;
10346 }
10347
10348 /*
10349 * The result is used as the new evaluation locset.
10350 */
10351 xmlXPathFreeObject(obj);
10352 ctxt->context->node = NULL;
10353 ctxt->context->contextSize = -1;
10354 ctxt->context->proximityPosition = -1;
10355 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10356 ctxt->context->node = oldnode;
10357 return (total);
10358 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010359#endif /* LIBXML_XPTR_ENABLED */
10360
Daniel Veillardf06307e2001-07-03 10:35:50 +000010361 /*
10362 * Extract the old set, and then evaluate the result of the
10363 * expression for all the element in the set. use it to grow
10364 * up a new set.
10365 */
10366 CHECK_TYPE0(XPATH_NODESET);
10367 obj = valuePop(ctxt);
10368 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010369
Daniel Veillardf06307e2001-07-03 10:35:50 +000010370 oldnode = ctxt->context->node;
10371 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010372
Daniel Veillardf06307e2001-07-03 10:35:50 +000010373 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10374 ctxt->context->contextSize = 0;
10375 ctxt->context->proximityPosition = 0;
10376 if (op->ch2 != -1)
10377 total +=
10378 xmlXPathCompOpEval(ctxt,
10379 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010380 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010381 res = valuePop(ctxt);
10382 if (res != NULL)
10383 xmlXPathFreeObject(res);
10384 valuePush(ctxt, obj);
10385 ctxt->context->node = oldnode;
10386 CHECK_ERROR0;
10387 } else {
10388 /*
10389 * Initialize the new set.
10390 */
10391 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010392
Daniel Veillardf06307e2001-07-03 10:35:50 +000010393 for (i = 0; i < oldset->nodeNr; i++) {
10394 /*
10395 * Run the evaluation with a node list made of
10396 * a single item in the nodeset.
10397 */
10398 ctxt->context->node = oldset->nodeTab[i];
10399 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10400 valuePush(ctxt, tmp);
10401 ctxt->context->contextSize = oldset->nodeNr;
10402 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010403
Daniel Veillardf06307e2001-07-03 10:35:50 +000010404 if (op->ch2 != -1)
10405 total +=
10406 xmlXPathCompOpEval(ctxt,
10407 &comp->steps[op->ch2]);
10408 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010409
Daniel Veillardf06307e2001-07-03 10:35:50 +000010410 /*
10411 * The result of the evaluation need to be tested to
10412 * decided whether the filter succeeded or not
10413 */
10414 res = valuePop(ctxt);
10415 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10416 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10417 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010418
Daniel Veillardf06307e2001-07-03 10:35:50 +000010419 /*
10420 * Cleanup
10421 */
10422 if (res != NULL)
10423 xmlXPathFreeObject(res);
10424 if (ctxt->value == tmp) {
10425 res = valuePop(ctxt);
10426 xmlXPathFreeObject(res);
10427 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010428
Daniel Veillardf06307e2001-07-03 10:35:50 +000010429 ctxt->context->node = NULL;
10430 }
10431
10432 /*
10433 * The result is used as the new evaluation set.
10434 */
10435 xmlXPathFreeObject(obj);
10436 ctxt->context->node = NULL;
10437 ctxt->context->contextSize = -1;
10438 ctxt->context->proximityPosition = -1;
10439 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10440 }
10441 ctxt->context->node = oldnode;
10442 return (total);
10443 }
10444 case XPATH_OP_SORT:
10445 if (op->ch1 != -1)
10446 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010447 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010448 if ((ctxt->value != NULL) &&
10449 (ctxt->value->type == XPATH_NODESET) &&
10450 (ctxt->value->nodesetval != NULL))
10451 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10452 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010453#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010454 case XPATH_OP_RANGETO:{
10455 xmlXPathObjectPtr range;
10456 xmlXPathObjectPtr res, obj;
10457 xmlXPathObjectPtr tmp;
10458 xmlLocationSetPtr newset = NULL;
10459 xmlNodeSetPtr oldset;
10460 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010461
Daniel Veillardf06307e2001-07-03 10:35:50 +000010462 if (op->ch1 != -1)
10463 total +=
10464 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10465 if (op->ch2 == -1)
10466 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010467
Daniel Veillardf06307e2001-07-03 10:35:50 +000010468 CHECK_TYPE0(XPATH_NODESET);
10469 obj = valuePop(ctxt);
10470 oldset = obj->nodesetval;
10471 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010472
Daniel Veillardf06307e2001-07-03 10:35:50 +000010473 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010474
Daniel Veillardf06307e2001-07-03 10:35:50 +000010475 if (oldset != NULL) {
10476 for (i = 0; i < oldset->nodeNr; i++) {
10477 /*
10478 * Run the evaluation with a node list made of a single item
10479 * in the nodeset.
10480 */
10481 ctxt->context->node = oldset->nodeTab[i];
10482 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10483 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010484
Daniel Veillardf06307e2001-07-03 10:35:50 +000010485 if (op->ch2 != -1)
10486 total +=
10487 xmlXPathCompOpEval(ctxt,
10488 &comp->steps[op->ch2]);
10489 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010490
Daniel Veillardf06307e2001-07-03 10:35:50 +000010491 /*
10492 * The result of the evaluation need to be tested to
10493 * decided whether the filter succeeded or not
10494 */
10495 res = valuePop(ctxt);
10496 range =
10497 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10498 res);
10499 if (range != NULL) {
10500 xmlXPtrLocationSetAdd(newset, range);
10501 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010502
Daniel Veillardf06307e2001-07-03 10:35:50 +000010503 /*
10504 * Cleanup
10505 */
10506 if (res != NULL)
10507 xmlXPathFreeObject(res);
10508 if (ctxt->value == tmp) {
10509 res = valuePop(ctxt);
10510 xmlXPathFreeObject(res);
10511 }
10512
10513 ctxt->context->node = NULL;
10514 }
10515 }
10516
10517 /*
10518 * The result is used as the new evaluation set.
10519 */
10520 xmlXPathFreeObject(obj);
10521 ctxt->context->node = NULL;
10522 ctxt->context->contextSize = -1;
10523 ctxt->context->proximityPosition = -1;
10524 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
10525 return (total);
10526 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010527#endif /* LIBXML_XPTR_ENABLED */
10528 }
10529 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010530 "XPath: unknown precompiled operation %d\n", op->op);
10531 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010532}
10533
10534/**
10535 * xmlXPathRunEval:
10536 * @ctxt: the XPath parser context with the compiled expression
10537 *
10538 * Evaluate the Precompiled XPath expression in the given context.
10539 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010540static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010541xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10542 xmlXPathCompExprPtr comp;
10543
10544 if ((ctxt == NULL) || (ctxt->comp == NULL))
10545 return;
10546
10547 if (ctxt->valueTab == NULL) {
10548 /* Allocate the value stack */
10549 ctxt->valueTab = (xmlXPathObjectPtr *)
10550 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10551 if (ctxt->valueTab == NULL) {
10552 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010553 }
10554 ctxt->valueNr = 0;
10555 ctxt->valueMax = 10;
10556 ctxt->value = NULL;
10557 }
10558 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000010559 if(comp->last < 0) {
10560 xmlGenericError(xmlGenericErrorContext,
10561 "xmlXPathRunEval: last is less than zero\n");
10562 return;
10563 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010564 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10565}
10566
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010567/************************************************************************
10568 * *
10569 * Public interfaces *
10570 * *
10571 ************************************************************************/
10572
10573/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010574 * xmlXPathEvalPredicate:
10575 * @ctxt: the XPath context
10576 * @res: the Predicate Expression evaluation result
10577 *
10578 * Evaluate a predicate result for the current node.
10579 * A PredicateExpr is evaluated by evaluating the Expr and converting
10580 * the result to a boolean. If the result is a number, the result will
10581 * be converted to true if the number is equal to the position of the
10582 * context node in the context node list (as returned by the position
10583 * function) and will be converted to false otherwise; if the result
10584 * is not a number, then the result will be converted as if by a call
10585 * to the boolean function.
10586 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010587 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010588 */
10589int
10590xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
10591 if (res == NULL) return(0);
10592 switch (res->type) {
10593 case XPATH_BOOLEAN:
10594 return(res->boolval);
10595 case XPATH_NUMBER:
10596 return(res->floatval == ctxt->proximityPosition);
10597 case XPATH_NODESET:
10598 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010599 if (res->nodesetval == NULL)
10600 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010601 return(res->nodesetval->nodeNr != 0);
10602 case XPATH_STRING:
10603 return((res->stringval != NULL) &&
10604 (xmlStrlen(res->stringval) != 0));
10605 default:
10606 STRANGE
10607 }
10608 return(0);
10609}
10610
10611/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010612 * xmlXPathEvaluatePredicateResult:
10613 * @ctxt: the XPath Parser context
10614 * @res: the Predicate Expression evaluation result
10615 *
10616 * Evaluate a predicate result for the current node.
10617 * A PredicateExpr is evaluated by evaluating the Expr and converting
10618 * the result to a boolean. If the result is a number, the result will
10619 * be converted to true if the number is equal to the position of the
10620 * context node in the context node list (as returned by the position
10621 * function) and will be converted to false otherwise; if the result
10622 * is not a number, then the result will be converted as if by a call
10623 * to the boolean function.
10624 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010625 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010626 */
10627int
10628xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10629 xmlXPathObjectPtr res) {
10630 if (res == NULL) return(0);
10631 switch (res->type) {
10632 case XPATH_BOOLEAN:
10633 return(res->boolval);
10634 case XPATH_NUMBER:
10635 return(res->floatval == ctxt->context->proximityPosition);
10636 case XPATH_NODESET:
10637 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000010638 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000010639 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010640 return(res->nodesetval->nodeNr != 0);
10641 case XPATH_STRING:
10642 return((res->stringval != NULL) &&
10643 (xmlStrlen(res->stringval) != 0));
10644 default:
10645 STRANGE
10646 }
10647 return(0);
10648}
10649
10650/**
10651 * xmlXPathCompile:
10652 * @str: the XPath expression
10653 *
10654 * Compile an XPath expression
10655 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000010656 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010657 * the caller has to free the object.
10658 */
10659xmlXPathCompExprPtr
10660xmlXPathCompile(const xmlChar *str) {
10661 xmlXPathParserContextPtr ctxt;
10662 xmlXPathCompExprPtr comp;
10663
10664 xmlXPathInit();
10665
10666 ctxt = xmlXPathNewParserContext(str, NULL);
10667 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010668
Daniel Veillard40af6492001-04-22 08:50:55 +000010669 if (*ctxt->cur != 0) {
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010670 /*
10671 * aleksey: in some cases this line prints *second* error message
10672 * (see bug #78858) and probably this should be fixed.
10673 * However, we are not sure that all error messages are printed
10674 * out in other places. It's not critical so we leave it as-is for now
10675 */
Daniel Veillard40af6492001-04-22 08:50:55 +000010676 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10677 comp = NULL;
10678 } else {
10679 comp = ctxt->comp;
10680 ctxt->comp = NULL;
10681 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010682 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010683 if (comp != NULL) {
Daniel Veillardceb09b92002-10-04 11:46:37 +000010684 comp->expr = xmlStrdup(str);
10685#ifdef DEBUG_EVAL_COUNTS
Daniel Veillardf06307e2001-07-03 10:35:50 +000010686 comp->string = xmlStrdup(str);
10687 comp->nb = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010688#endif
Daniel Veillardceb09b92002-10-04 11:46:37 +000010689 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010690 return(comp);
10691}
10692
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010693/**
10694 * xmlXPathCompiledEval:
10695 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000010696 * @ctx: the XPath context
10697 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010698 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000010699 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010700 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000010701 * the caller has to free the object.
10702 */
10703xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010704xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000010705 xmlXPathParserContextPtr ctxt;
10706 xmlXPathObjectPtr res, tmp, init = NULL;
10707 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000010708#ifndef LIBXML_THREAD_ENABLED
10709 static int reentance = 0;
10710#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010711
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010712 if ((comp == NULL) || (ctx == NULL))
10713 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010714 xmlXPathInit();
10715
10716 CHECK_CONTEXT(ctx)
10717
Daniel Veillard81463942001-10-16 12:34:39 +000010718#ifndef LIBXML_THREAD_ENABLED
10719 reentance++;
10720 if (reentance > 1)
10721 xmlXPathDisableOptimizer = 1;
10722#endif
10723
Daniel Veillardf06307e2001-07-03 10:35:50 +000010724#ifdef DEBUG_EVAL_COUNTS
10725 comp->nb++;
10726 if ((comp->string != NULL) && (comp->nb > 100)) {
10727 fprintf(stderr, "100 x %s\n", comp->string);
10728 comp->nb = 0;
10729 }
10730#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010731 ctxt = xmlXPathCompParserContext(comp, ctx);
10732 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010733
10734 if (ctxt->value == NULL) {
10735 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010736 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000010737 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000010738 } else {
10739 res = valuePop(ctxt);
10740 }
10741
Daniel Veillardf06307e2001-07-03 10:35:50 +000010742
Owen Taylor3473f882001-02-23 17:55:21 +000010743 do {
10744 tmp = valuePop(ctxt);
10745 if (tmp != NULL) {
10746 if (tmp != init)
10747 stack++;
10748 xmlXPathFreeObject(tmp);
10749 }
10750 } while (tmp != NULL);
10751 if ((stack != 0) && (res != NULL)) {
10752 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010753 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000010754 stack);
10755 }
10756 if (ctxt->error != XPATH_EXPRESSION_OK) {
10757 xmlXPathFreeObject(res);
10758 res = NULL;
10759 }
10760
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010761
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010762 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010763 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000010764#ifndef LIBXML_THREAD_ENABLED
10765 reentance--;
10766#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010767 return(res);
10768}
10769
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010770/**
10771 * xmlXPathEvalExpr:
10772 * @ctxt: the XPath Parser context
10773 *
10774 * Parse and evaluate an XPath expression in the given context,
10775 * then push the result on the context stack
10776 */
10777void
10778xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
10779 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010780 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010781 xmlXPathRunEval(ctxt);
10782}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010783
10784/**
10785 * xmlXPathEval:
10786 * @str: the XPath expression
10787 * @ctx: the XPath context
10788 *
10789 * Evaluate the XPath Location Path in the given context.
10790 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010791 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010792 * the caller has to free the object.
10793 */
10794xmlXPathObjectPtr
10795xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
10796 xmlXPathParserContextPtr ctxt;
10797 xmlXPathObjectPtr res, tmp, init = NULL;
10798 int stack = 0;
10799
10800 xmlXPathInit();
10801
10802 CHECK_CONTEXT(ctx)
10803
10804 ctxt = xmlXPathNewParserContext(str, ctx);
10805 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010806
10807 if (ctxt->value == NULL) {
10808 xmlGenericError(xmlGenericErrorContext,
10809 "xmlXPathEval: evaluation failed\n");
10810 res = NULL;
10811 } else if (*ctxt->cur != 0) {
10812 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10813 res = NULL;
10814 } else {
10815 res = valuePop(ctxt);
10816 }
10817
10818 do {
10819 tmp = valuePop(ctxt);
10820 if (tmp != NULL) {
10821 if (tmp != init)
10822 stack++;
10823 xmlXPathFreeObject(tmp);
10824 }
10825 } while (tmp != NULL);
10826 if ((stack != 0) && (res != NULL)) {
10827 xmlGenericError(xmlGenericErrorContext,
10828 "xmlXPathEval: %d object left on the stack\n",
10829 stack);
10830 }
10831 if (ctxt->error != XPATH_EXPRESSION_OK) {
10832 xmlXPathFreeObject(res);
10833 res = NULL;
10834 }
10835
Owen Taylor3473f882001-02-23 17:55:21 +000010836 xmlXPathFreeParserContext(ctxt);
10837 return(res);
10838}
10839
10840/**
10841 * xmlXPathEvalExpression:
10842 * @str: the XPath expression
10843 * @ctxt: the XPath context
10844 *
10845 * Evaluate the XPath expression in the given context.
10846 *
10847 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
10848 * the caller has to free the object.
10849 */
10850xmlXPathObjectPtr
10851xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
10852 xmlXPathParserContextPtr pctxt;
10853 xmlXPathObjectPtr res, tmp;
10854 int stack = 0;
10855
10856 xmlXPathInit();
10857
10858 CHECK_CONTEXT(ctxt)
10859
10860 pctxt = xmlXPathNewParserContext(str, ctxt);
10861 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010862
10863 if (*pctxt->cur != 0) {
10864 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10865 res = NULL;
10866 } else {
10867 res = valuePop(pctxt);
10868 }
10869 do {
10870 tmp = valuePop(pctxt);
10871 if (tmp != NULL) {
10872 xmlXPathFreeObject(tmp);
10873 stack++;
10874 }
10875 } while (tmp != NULL);
10876 if ((stack != 0) && (res != NULL)) {
10877 xmlGenericError(xmlGenericErrorContext,
10878 "xmlXPathEvalExpression: %d object left on the stack\n",
10879 stack);
10880 }
10881 xmlXPathFreeParserContext(pctxt);
10882 return(res);
10883}
10884
Daniel Veillard42766c02002-08-22 20:52:17 +000010885/************************************************************************
10886 * *
10887 * Extra functions not pertaining to the XPath spec *
10888 * *
10889 ************************************************************************/
10890/**
10891 * xmlXPathEscapeUriFunction:
10892 * @ctxt: the XPath Parser context
10893 * @nargs: the number of arguments
10894 *
10895 * Implement the escape-uri() XPath function
10896 * string escape-uri(string $str, bool $escape-reserved)
10897 *
10898 * This function applies the URI escaping rules defined in section 2 of [RFC
10899 * 2396] to the string supplied as $uri-part, which typically represents all
10900 * or part of a URI. The effect of the function is to replace any special
10901 * character in the string by an escape sequence of the form %xx%yy...,
10902 * where xxyy... is the hexadecimal representation of the octets used to
10903 * represent the character in UTF-8.
10904 *
10905 * The set of characters that are escaped depends on the setting of the
10906 * boolean argument $escape-reserved.
10907 *
10908 * If $escape-reserved is true, all characters are escaped other than lower
10909 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
10910 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
10911 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
10912 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
10913 * A-F).
10914 *
10915 * If $escape-reserved is false, the behavior differs in that characters
10916 * referred to in [RFC 2396] as reserved characters are not escaped. These
10917 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
10918 *
10919 * [RFC 2396] does not define whether escaped URIs should use lower case or
10920 * upper case for hexadecimal digits. To ensure that escaped URIs can be
10921 * compared using string comparison functions, this function must always use
10922 * the upper-case letters A-F.
10923 *
10924 * Generally, $escape-reserved should be set to true when escaping a string
10925 * that is to form a single part of a URI, and to false when escaping an
10926 * entire URI or URI reference.
10927 *
10928 * In the case of non-ascii characters, the string is encoded according to
10929 * utf-8 and then converted according to RFC 2396.
10930 *
10931 * Examples
10932 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
10933 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
10934 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
10935 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
10936 *
10937 */
Daniel Veillard118aed72002-09-24 14:13:13 +000010938static void
Daniel Veillard42766c02002-08-22 20:52:17 +000010939xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
10940 xmlXPathObjectPtr str;
10941 int escape_reserved;
10942 xmlBufferPtr target;
10943 xmlChar *cptr;
10944 xmlChar escape[4];
10945
10946 CHECK_ARITY(2);
10947
10948 escape_reserved = xmlXPathPopBoolean(ctxt);
10949
10950 CAST_TO_STRING;
10951 str = valuePop(ctxt);
10952
10953 target = xmlBufferCreate();
10954
10955 escape[0] = '%';
10956 escape[3] = 0;
10957
10958 if (target) {
10959 for (cptr = str->stringval; *cptr; cptr++) {
10960 if ((*cptr >= 'A' && *cptr <= 'Z') ||
10961 (*cptr >= 'a' && *cptr <= 'z') ||
10962 (*cptr >= '0' && *cptr <= '9') ||
10963 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
10964 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
10965 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
10966 (*cptr == '%' &&
10967 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
10968 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
10969 (cptr[1] >= '0' && cptr[1] <= '9')) &&
10970 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
10971 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
10972 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
10973 (!escape_reserved &&
10974 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
10975 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
10976 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
10977 *cptr == ','))) {
10978 xmlBufferAdd(target, cptr, 1);
10979 } else {
10980 if ((*cptr >> 4) < 10)
10981 escape[1] = '0' + (*cptr >> 4);
10982 else
10983 escape[1] = 'A' - 10 + (*cptr >> 4);
10984 if ((*cptr & 0xF) < 10)
10985 escape[2] = '0' + (*cptr & 0xF);
10986 else
10987 escape[2] = 'A' - 10 + (*cptr & 0xF);
10988
10989 xmlBufferAdd(target, &escape[0], 3);
10990 }
10991 }
10992 }
10993 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
10994 xmlBufferFree(target);
10995 xmlXPathFreeObject(str);
10996}
10997
Owen Taylor3473f882001-02-23 17:55:21 +000010998/**
10999 * xmlXPathRegisterAllFunctions:
11000 * @ctxt: the XPath context
11001 *
11002 * Registers all default XPath functions in this context
11003 */
11004void
11005xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
11006{
11007 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
11008 xmlXPathBooleanFunction);
11009 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
11010 xmlXPathCeilingFunction);
11011 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
11012 xmlXPathCountFunction);
11013 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
11014 xmlXPathConcatFunction);
11015 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
11016 xmlXPathContainsFunction);
11017 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
11018 xmlXPathIdFunction);
11019 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
11020 xmlXPathFalseFunction);
11021 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
11022 xmlXPathFloorFunction);
11023 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
11024 xmlXPathLastFunction);
11025 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
11026 xmlXPathLangFunction);
11027 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
11028 xmlXPathLocalNameFunction);
11029 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
11030 xmlXPathNotFunction);
11031 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
11032 xmlXPathNameFunction);
11033 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
11034 xmlXPathNamespaceURIFunction);
11035 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
11036 xmlXPathNormalizeFunction);
11037 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
11038 xmlXPathNumberFunction);
11039 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
11040 xmlXPathPositionFunction);
11041 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
11042 xmlXPathRoundFunction);
11043 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
11044 xmlXPathStringFunction);
11045 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
11046 xmlXPathStringLengthFunction);
11047 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
11048 xmlXPathStartsWithFunction);
11049 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
11050 xmlXPathSubstringFunction);
11051 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
11052 xmlXPathSubstringBeforeFunction);
11053 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
11054 xmlXPathSubstringAfterFunction);
11055 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
11056 xmlXPathSumFunction);
11057 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
11058 xmlXPathTrueFunction);
11059 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
11060 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000011061
11062 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
11063 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
11064 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000011065}
11066
11067#endif /* LIBXML_XPATH_ENABLED */