blob: 6aca07987e54d4d8e5b5458f7c5c7291a9338c4a [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/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001343 * xmlXPathOrderDocElems:
1344 * @doc: an input document
1345 *
1346 * Call this routine to speed up XPath computation on static documents.
1347 * This stamps all the element nodes with the document order
1348 * Like for line information, the order is kept in the element->content
1349 * field, the value stored is actually - the node number (startting at -1)
1350 * to be able to differenciate from line numbers.
1351 *
1352 * Returns the number of element found in the document or -1 in case
1353 * of error.
1354 */
1355long
1356xmlXPathOrderDocElems(xmlDocPtr doc) {
1357 long count = 0;
1358 xmlNodePtr cur;
1359
1360 if (doc == NULL)
1361 return(-1);
1362 cur = doc->children;
1363 while (cur != NULL) {
1364 if (cur->type == XML_ELEMENT_NODE) {
1365 cur->content = (void *) (-(++count));
1366 if (cur->children != NULL) {
1367 cur = cur->children;
1368 continue;
1369 }
1370 }
1371 if (cur->next != NULL) {
1372 cur = cur->next;
1373 continue;
1374 }
1375 do {
1376 cur = cur->parent;
1377 if (cur == NULL)
1378 break;
1379 if (cur == (xmlNodePtr) doc) {
1380 cur = NULL;
1381 break;
1382 }
1383 if (cur->next != NULL) {
1384 cur = cur->next;
1385 break;
1386 }
1387 } while (cur != NULL);
1388 }
1389 return(count);
1390}
1391
1392/**
Owen Taylor3473f882001-02-23 17:55:21 +00001393 * xmlXPathCmpNodes:
1394 * @node1: the first node
1395 * @node2: the second node
1396 *
1397 * Compare two nodes w.r.t document order
1398 *
1399 * Returns -2 in case of error 1 if first point < second point, 0 if
1400 * that's the same node, -1 otherwise
1401 */
1402int
1403xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1404 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001405 int attr1 = 0, attr2 = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001406 xmlNodePtr cur, root;
1407
1408 if ((node1 == NULL) || (node2 == NULL))
1409 return(-2);
1410 /*
1411 * a couple of optimizations which will avoid computations in most cases
1412 */
Daniel Veillardedfd5882003-03-07 14:20:40 +00001413 if (node1->type == XML_ATTRIBUTE_NODE) {
1414 attr1 = 1;
1415 node1 = node1->parent;
1416 }
1417 if (node2->type == XML_ATTRIBUTE_NODE) {
1418 attr2 = 1;
1419 node2 = node2->parent;
1420 }
1421 if (node1 == node2) {
1422 if (attr1 == attr2)
1423 return(0);
1424 if (attr2 == 1)
1425 return(1);
1426 return(-1);
1427 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00001428 if ((node1->type == XML_NAMESPACE_DECL) ||
1429 (node2->type == XML_NAMESPACE_DECL))
1430 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001431 if (node1 == node2->prev)
1432 return(1);
1433 if (node1 == node2->next)
1434 return(-1);
1435
1436 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001437 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001438 */
1439 if ((node1->type == XML_ELEMENT_NODE) &&
1440 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001441 (0 > (long) node1->content) &&
1442 (0 > (long) node2->content) &&
1443 (node1->doc == node2->doc)) {
1444 long l1, l2;
1445
1446 l1 = -((long) node1->content);
1447 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001448 if (l1 < l2)
1449 return(1);
1450 if (l1 > l2)
1451 return(-1);
1452 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001453
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001454 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001455 * compute depth to root
1456 */
1457 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1458 if (cur == node1)
1459 return(1);
1460 depth2++;
1461 }
1462 root = cur;
1463 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1464 if (cur == node2)
1465 return(-1);
1466 depth1++;
1467 }
1468 /*
1469 * Distinct document (or distinct entities :-( ) case.
1470 */
1471 if (root != cur) {
1472 return(-2);
1473 }
1474 /*
1475 * get the nearest common ancestor.
1476 */
1477 while (depth1 > depth2) {
1478 depth1--;
1479 node1 = node1->parent;
1480 }
1481 while (depth2 > depth1) {
1482 depth2--;
1483 node2 = node2->parent;
1484 }
1485 while (node1->parent != node2->parent) {
1486 node1 = node1->parent;
1487 node2 = node2->parent;
1488 /* should not happen but just in case ... */
1489 if ((node1 == NULL) || (node2 == NULL))
1490 return(-2);
1491 }
1492 /*
1493 * Find who's first.
1494 */
1495 if (node1 == node2->next)
1496 return(-1);
1497 for (cur = node1->next;cur != NULL;cur = cur->next)
1498 if (cur == node2)
1499 return(1);
1500 return(-1); /* assume there is no sibling list corruption */
1501}
1502
1503/**
1504 * xmlXPathNodeSetSort:
1505 * @set: the node set
1506 *
1507 * Sort the node set in document order
1508 */
1509void
1510xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001511 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001512 xmlNodePtr tmp;
1513
1514 if (set == NULL)
1515 return;
1516
1517 /* Use Shell's sort to sort the node-set */
1518 len = set->nodeNr;
1519 for (incr = len / 2; incr > 0; incr /= 2) {
1520 for (i = incr; i < len; i++) {
1521 j = i - incr;
1522 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001523 if (xmlXPathCmpNodes(set->nodeTab[j],
1524 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001525 tmp = set->nodeTab[j];
1526 set->nodeTab[j] = set->nodeTab[j + incr];
1527 set->nodeTab[j + incr] = tmp;
1528 j -= incr;
1529 } else
1530 break;
1531 }
1532 }
1533 }
1534}
1535
1536#define XML_NODESET_DEFAULT 10
1537/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001538 * xmlXPathNodeSetDupNs:
1539 * @node: the parent node of the namespace XPath node
1540 * @ns: the libxml namespace declaration node.
1541 *
1542 * Namespace node in libxml don't match the XPath semantic. In a node set
1543 * the namespace nodes are duplicated and the next pointer is set to the
1544 * parent node in the XPath semantic.
1545 *
1546 * Returns the newly created object.
1547 */
1548static xmlNodePtr
1549xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
1550 xmlNsPtr cur;
1551
1552 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1553 return(NULL);
1554 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
1555 return((xmlNodePtr) ns);
1556
1557 /*
1558 * Allocate a new Namespace and fill the fields.
1559 */
1560 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1561 if (cur == NULL) {
1562 xmlGenericError(xmlGenericErrorContext,
1563 "xmlXPathNodeSetDupNs : malloc failed\n");
1564 return(NULL);
1565 }
1566 memset(cur, 0, sizeof(xmlNs));
1567 cur->type = XML_NAMESPACE_DECL;
1568 if (ns->href != NULL)
1569 cur->href = xmlStrdup(ns->href);
1570 if (ns->prefix != NULL)
1571 cur->prefix = xmlStrdup(ns->prefix);
1572 cur->next = (xmlNsPtr) node;
1573 return((xmlNodePtr) cur);
1574}
1575
1576/**
1577 * xmlXPathNodeSetFreeNs:
1578 * @ns: the XPath namespace node found in a nodeset.
1579 *
1580 * Namespace node in libxml don't match the XPath semantic. In a node set
1581 * the namespace nodes are duplicated and the next pointer is set to the
1582 * parent node in the XPath semantic. Check if such a node need to be freed
1583 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001584void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001585xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
1586 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1587 return;
1588
1589 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
1590 if (ns->href != NULL)
1591 xmlFree((xmlChar *)ns->href);
1592 if (ns->prefix != NULL)
1593 xmlFree((xmlChar *)ns->prefix);
1594 xmlFree(ns);
1595 }
1596}
1597
1598/**
Owen Taylor3473f882001-02-23 17:55:21 +00001599 * xmlXPathNodeSetCreate:
1600 * @val: an initial xmlNodePtr, or NULL
1601 *
1602 * Create a new xmlNodeSetPtr of type double and of value @val
1603 *
1604 * Returns the newly created object.
1605 */
1606xmlNodeSetPtr
1607xmlXPathNodeSetCreate(xmlNodePtr val) {
1608 xmlNodeSetPtr ret;
1609
1610 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1611 if (ret == NULL) {
1612 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001613 "xmlXPathNodeSetCreate: out of memory\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001614 return(NULL);
1615 }
1616 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1617 if (val != NULL) {
1618 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1619 sizeof(xmlNodePtr));
1620 if (ret->nodeTab == NULL) {
1621 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001622 "xmlXPathNodeSetCreate: out of memory\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001623 return(NULL);
1624 }
1625 memset(ret->nodeTab, 0 ,
1626 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1627 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001628 if (val->type == XML_NAMESPACE_DECL) {
1629 xmlNsPtr ns = (xmlNsPtr) val;
1630
1631 ret->nodeTab[ret->nodeNr++] =
1632 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1633 } else
1634 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001635 }
1636 return(ret);
1637}
1638
1639/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001640 * xmlXPathNodeSetContains:
1641 * @cur: the node-set
1642 * @val: the node
1643 *
1644 * checks whether @cur contains @val
1645 *
1646 * Returns true (1) if @cur contains @val, false (0) otherwise
1647 */
1648int
1649xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1650 int i;
1651
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001652 if (val->type == XML_NAMESPACE_DECL) {
1653 for (i = 0; i < cur->nodeNr; i++) {
1654 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1655 xmlNsPtr ns1, ns2;
1656
1657 ns1 = (xmlNsPtr) val;
1658 ns2 = (xmlNsPtr) cur->nodeTab[i];
1659 if (ns1 == ns2)
1660 return(1);
1661 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
1662 (xmlStrEqual(ns1->prefix, ns2->prefix)))
1663 return(1);
1664 }
1665 }
1666 } else {
1667 for (i = 0; i < cur->nodeNr; i++) {
1668 if (cur->nodeTab[i] == val)
1669 return(1);
1670 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001671 }
1672 return(0);
1673}
1674
1675/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001676 * xmlXPathNodeSetAddNs:
1677 * @cur: the initial node set
1678 * @node: the hosting node
1679 * @ns: a the namespace node
1680 *
1681 * add a new namespace node to an existing NodeSet
1682 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00001683void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001684xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
1685 int i;
1686
1687 if ((ns == NULL) || (node == NULL) || (ns->type != XML_NAMESPACE_DECL) ||
1688 (node->type != XML_ELEMENT_NODE))
1689 return;
1690
1691 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1692 /*
1693 * check against doublons
1694 */
1695 for (i = 0;i < cur->nodeNr;i++) {
1696 if ((cur->nodeTab[i] != NULL) &&
1697 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00001698 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001699 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
1700 return;
1701 }
1702
1703 /*
1704 * grow the nodeTab if needed
1705 */
1706 if (cur->nodeMax == 0) {
1707 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1708 sizeof(xmlNodePtr));
1709 if (cur->nodeTab == NULL) {
1710 xmlGenericError(xmlGenericErrorContext,
1711 "xmlXPathNodeSetAdd: out of memory\n");
1712 return;
1713 }
1714 memset(cur->nodeTab, 0 ,
1715 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1716 cur->nodeMax = XML_NODESET_DEFAULT;
1717 } else if (cur->nodeNr == cur->nodeMax) {
1718 xmlNodePtr *temp;
1719
1720 cur->nodeMax *= 2;
1721 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1722 sizeof(xmlNodePtr));
1723 if (temp == NULL) {
1724 xmlGenericError(xmlGenericErrorContext,
1725 "xmlXPathNodeSetAdd: out of memory\n");
1726 return;
1727 }
1728 cur->nodeTab = temp;
1729 }
1730 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
1731}
1732
1733/**
Owen Taylor3473f882001-02-23 17:55:21 +00001734 * xmlXPathNodeSetAdd:
1735 * @cur: the initial node set
1736 * @val: a new xmlNodePtr
1737 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001738 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00001739 */
1740void
1741xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1742 int i;
1743
1744 if (val == NULL) return;
1745
Daniel Veillardef0b4502003-03-24 13:57:34 +00001746#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001747 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1748 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001749#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001750
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001751 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001752 /*
1753 * check against doublons
1754 */
1755 for (i = 0;i < cur->nodeNr;i++)
1756 if (cur->nodeTab[i] == val) return;
1757
1758 /*
1759 * grow the nodeTab if needed
1760 */
1761 if (cur->nodeMax == 0) {
1762 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1763 sizeof(xmlNodePtr));
1764 if (cur->nodeTab == NULL) {
1765 xmlGenericError(xmlGenericErrorContext,
1766 "xmlXPathNodeSetAdd: out of memory\n");
1767 return;
1768 }
1769 memset(cur->nodeTab, 0 ,
1770 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1771 cur->nodeMax = XML_NODESET_DEFAULT;
1772 } else if (cur->nodeNr == cur->nodeMax) {
1773 xmlNodePtr *temp;
1774
1775 cur->nodeMax *= 2;
1776 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1777 sizeof(xmlNodePtr));
1778 if (temp == NULL) {
1779 xmlGenericError(xmlGenericErrorContext,
1780 "xmlXPathNodeSetAdd: out of memory\n");
1781 return;
1782 }
1783 cur->nodeTab = temp;
1784 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001785 if (val->type == XML_NAMESPACE_DECL) {
1786 xmlNsPtr ns = (xmlNsPtr) val;
1787
1788 cur->nodeTab[cur->nodeNr++] =
1789 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1790 } else
1791 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001792}
1793
1794/**
1795 * xmlXPathNodeSetAddUnique:
1796 * @cur: the initial node set
1797 * @val: a new xmlNodePtr
1798 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001799 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00001800 * when we are sure the node is not already in the set.
1801 */
1802void
1803xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1804 if (val == NULL) return;
1805
Daniel Veillardef0b4502003-03-24 13:57:34 +00001806#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001807 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1808 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001809#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001810
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001811 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001812 /*
1813 * grow the nodeTab if needed
1814 */
1815 if (cur->nodeMax == 0) {
1816 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1817 sizeof(xmlNodePtr));
1818 if (cur->nodeTab == NULL) {
1819 xmlGenericError(xmlGenericErrorContext,
1820 "xmlXPathNodeSetAddUnique: out of memory\n");
1821 return;
1822 }
1823 memset(cur->nodeTab, 0 ,
1824 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1825 cur->nodeMax = XML_NODESET_DEFAULT;
1826 } else if (cur->nodeNr == cur->nodeMax) {
1827 xmlNodePtr *temp;
1828
1829 cur->nodeMax *= 2;
1830 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1831 sizeof(xmlNodePtr));
1832 if (temp == NULL) {
1833 xmlGenericError(xmlGenericErrorContext,
1834 "xmlXPathNodeSetAddUnique: out of memory\n");
1835 return;
1836 }
1837 cur->nodeTab = temp;
1838 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001839 if (val->type == XML_NAMESPACE_DECL) {
1840 xmlNsPtr ns = (xmlNsPtr) val;
1841
1842 cur->nodeTab[cur->nodeNr++] =
1843 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1844 } else
1845 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001846}
1847
1848/**
1849 * xmlXPathNodeSetMerge:
1850 * @val1: the first NodeSet or NULL
1851 * @val2: the second NodeSet
1852 *
1853 * Merges two nodesets, all nodes from @val2 are added to @val1
1854 * if @val1 is NULL, a new set is created and copied from @val2
1855 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001856 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00001857 */
1858xmlNodeSetPtr
1859xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001860 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001861
1862 if (val2 == NULL) return(val1);
1863 if (val1 == NULL) {
1864 val1 = xmlXPathNodeSetCreate(NULL);
1865 }
1866
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001867 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001868 initNr = val1->nodeNr;
1869
1870 for (i = 0;i < val2->nodeNr;i++) {
1871 /*
1872 * check against doublons
1873 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001874 skip = 0;
1875 for (j = 0; j < initNr; j++) {
1876 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1877 skip = 1;
1878 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001879 } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) &&
1880 (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) {
1881 xmlNsPtr ns1, ns2;
1882 ns1 = (xmlNsPtr) val1->nodeTab[j];
1883 ns2 = (xmlNsPtr) val2->nodeTab[i];
1884 if ((ns1->next == ns2->next) &&
1885 (xmlStrEqual(ns1->prefix, ns2->prefix))) {
1886 skip = 1;
1887 break;
1888 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001889 }
1890 }
1891 if (skip)
1892 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00001893
1894 /*
1895 * grow the nodeTab if needed
1896 */
1897 if (val1->nodeMax == 0) {
1898 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1899 sizeof(xmlNodePtr));
1900 if (val1->nodeTab == NULL) {
1901 xmlGenericError(xmlGenericErrorContext,
1902 "xmlXPathNodeSetMerge: out of memory\n");
1903 return(NULL);
1904 }
1905 memset(val1->nodeTab, 0 ,
1906 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1907 val1->nodeMax = XML_NODESET_DEFAULT;
1908 } else if (val1->nodeNr == val1->nodeMax) {
1909 xmlNodePtr *temp;
1910
1911 val1->nodeMax *= 2;
1912 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1913 sizeof(xmlNodePtr));
1914 if (temp == NULL) {
1915 xmlGenericError(xmlGenericErrorContext,
1916 "xmlXPathNodeSetMerge: out of memory\n");
1917 return(NULL);
1918 }
1919 val1->nodeTab = temp;
1920 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001921 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1922 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1923
1924 val1->nodeTab[val1->nodeNr++] =
1925 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1926 } else
1927 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00001928 }
1929
1930 return(val1);
1931}
1932
1933/**
Daniel Veillard75be0132002-03-13 10:03:35 +00001934 * xmlXPathNodeSetMergeUnique:
1935 * @val1: the first NodeSet or NULL
1936 * @val2: the second NodeSet
1937 *
1938 * Merges two nodesets, all nodes from @val2 are added to @val1
1939 * if @val1 is NULL, a new set is created and copied from @val2
1940 *
1941 * Returns @val1 once extended or NULL in case of error.
1942 */
1943static xmlNodeSetPtr
1944xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
1945 int i, initNr;
1946
1947 if (val2 == NULL) return(val1);
1948 if (val1 == NULL) {
1949 val1 = xmlXPathNodeSetCreate(NULL);
1950 }
1951
1952 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1953 initNr = val1->nodeNr;
1954
1955 for (i = 0;i < val2->nodeNr;i++) {
1956 /*
1957 * grow the nodeTab if needed
1958 */
1959 if (val1->nodeMax == 0) {
1960 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1961 sizeof(xmlNodePtr));
1962 if (val1->nodeTab == NULL) {
1963 xmlGenericError(xmlGenericErrorContext,
1964 "xmlXPathNodeSetMerge: out of memory\n");
1965 return(NULL);
1966 }
1967 memset(val1->nodeTab, 0 ,
1968 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1969 val1->nodeMax = XML_NODESET_DEFAULT;
1970 } else if (val1->nodeNr == val1->nodeMax) {
1971 xmlNodePtr *temp;
1972
1973 val1->nodeMax *= 2;
1974 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1975 sizeof(xmlNodePtr));
1976 if (temp == NULL) {
1977 xmlGenericError(xmlGenericErrorContext,
1978 "xmlXPathNodeSetMerge: out of memory\n");
1979 return(NULL);
1980 }
1981 val1->nodeTab = temp;
1982 }
1983 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1984 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1985
1986 val1->nodeTab[val1->nodeNr++] =
1987 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1988 } else
1989 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
1990 }
1991
1992 return(val1);
1993}
1994
1995/**
Owen Taylor3473f882001-02-23 17:55:21 +00001996 * xmlXPathNodeSetDel:
1997 * @cur: the initial node set
1998 * @val: an xmlNodePtr
1999 *
2000 * Removes an xmlNodePtr from an existing NodeSet
2001 */
2002void
2003xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
2004 int i;
2005
2006 if (cur == NULL) return;
2007 if (val == NULL) return;
2008
2009 /*
2010 * check against doublons
2011 */
2012 for (i = 0;i < cur->nodeNr;i++)
2013 if (cur->nodeTab[i] == val) break;
2014
2015 if (i >= cur->nodeNr) {
2016#ifdef DEBUG
2017 xmlGenericError(xmlGenericErrorContext,
2018 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
2019 val->name);
2020#endif
2021 return;
2022 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002023 if ((cur->nodeTab[i] != NULL) &&
2024 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
2025 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002026 cur->nodeNr--;
2027 for (;i < cur->nodeNr;i++)
2028 cur->nodeTab[i] = cur->nodeTab[i + 1];
2029 cur->nodeTab[cur->nodeNr] = NULL;
2030}
2031
2032/**
2033 * xmlXPathNodeSetRemove:
2034 * @cur: the initial node set
2035 * @val: the index to remove
2036 *
2037 * Removes an entry from an existing NodeSet list.
2038 */
2039void
2040xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
2041 if (cur == NULL) return;
2042 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002043 if ((cur->nodeTab[val] != NULL) &&
2044 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
2045 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00002046 cur->nodeNr--;
2047 for (;val < cur->nodeNr;val++)
2048 cur->nodeTab[val] = cur->nodeTab[val + 1];
2049 cur->nodeTab[cur->nodeNr] = NULL;
2050}
2051
2052/**
2053 * xmlXPathFreeNodeSet:
2054 * @obj: the xmlNodeSetPtr to free
2055 *
2056 * Free the NodeSet compound (not the actual nodes !).
2057 */
2058void
2059xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
2060 if (obj == NULL) return;
2061 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002062 int i;
2063
2064 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
2065 for (i = 0;i < obj->nodeNr;i++)
2066 if ((obj->nodeTab[i] != NULL) &&
2067 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
2068 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002069 xmlFree(obj->nodeTab);
2070 }
Owen Taylor3473f882001-02-23 17:55:21 +00002071 xmlFree(obj);
2072}
2073
2074/**
2075 * xmlXPathFreeValueTree:
2076 * @obj: the xmlNodeSetPtr to free
2077 *
2078 * Free the NodeSet compound and the actual tree, this is different
2079 * from xmlXPathFreeNodeSet()
2080 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002081static void
Owen Taylor3473f882001-02-23 17:55:21 +00002082xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
2083 int i;
2084
2085 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002086
2087 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002088 for (i = 0;i < obj->nodeNr;i++) {
2089 if (obj->nodeTab[i] != NULL) {
2090 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2091 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
2092 } else {
2093 xmlFreeNodeList(obj->nodeTab[i]);
2094 }
2095 }
2096 }
Owen Taylor3473f882001-02-23 17:55:21 +00002097 xmlFree(obj->nodeTab);
2098 }
Owen Taylor3473f882001-02-23 17:55:21 +00002099 xmlFree(obj);
2100}
2101
2102#if defined(DEBUG) || defined(DEBUG_STEP)
2103/**
2104 * xmlGenericErrorContextNodeSet:
2105 * @output: a FILE * for the output
2106 * @obj: the xmlNodeSetPtr to free
2107 *
2108 * Quick display of a NodeSet
2109 */
2110void
2111xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
2112 int i;
2113
2114 if (output == NULL) output = xmlGenericErrorContext;
2115 if (obj == NULL) {
2116 fprintf(output, "NodeSet == NULL !\n");
2117 return;
2118 }
2119 if (obj->nodeNr == 0) {
2120 fprintf(output, "NodeSet is empty\n");
2121 return;
2122 }
2123 if (obj->nodeTab == NULL) {
2124 fprintf(output, " nodeTab == NULL !\n");
2125 return;
2126 }
2127 for (i = 0; i < obj->nodeNr; i++) {
2128 if (obj->nodeTab[i] == NULL) {
2129 fprintf(output, " NULL !\n");
2130 return;
2131 }
2132 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
2133 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
2134 fprintf(output, " /");
2135 else if (obj->nodeTab[i]->name == NULL)
2136 fprintf(output, " noname!");
2137 else fprintf(output, " %s", obj->nodeTab[i]->name);
2138 }
2139 fprintf(output, "\n");
2140}
2141#endif
2142
2143/**
2144 * xmlXPathNewNodeSet:
2145 * @val: the NodePtr value
2146 *
2147 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2148 * it with the single Node @val
2149 *
2150 * Returns the newly created object.
2151 */
2152xmlXPathObjectPtr
2153xmlXPathNewNodeSet(xmlNodePtr val) {
2154 xmlXPathObjectPtr ret;
2155
2156 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2157 if (ret == NULL) {
2158 xmlGenericError(xmlGenericErrorContext,
2159 "xmlXPathNewNodeSet: out of memory\n");
2160 return(NULL);
2161 }
2162 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2163 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00002164 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002165 ret->nodesetval = xmlXPathNodeSetCreate(val);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002166 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002167 return(ret);
2168}
2169
2170/**
2171 * xmlXPathNewValueTree:
2172 * @val: the NodePtr value
2173 *
2174 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
2175 * it with the tree root @val
2176 *
2177 * Returns the newly created object.
2178 */
2179xmlXPathObjectPtr
2180xmlXPathNewValueTree(xmlNodePtr val) {
2181 xmlXPathObjectPtr ret;
2182
2183 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2184 if (ret == NULL) {
2185 xmlGenericError(xmlGenericErrorContext,
2186 "xmlXPathNewNodeSet: out of memory\n");
2187 return(NULL);
2188 }
2189 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2190 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002191 ret->boolval = 1;
2192 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00002193 ret->nodesetval = xmlXPathNodeSetCreate(val);
2194 return(ret);
2195}
2196
2197/**
2198 * xmlXPathNewNodeSetList:
2199 * @val: an existing NodeSet
2200 *
2201 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2202 * it with the Nodeset @val
2203 *
2204 * Returns the newly created object.
2205 */
2206xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002207xmlXPathNewNodeSetList(xmlNodeSetPtr val)
2208{
Owen Taylor3473f882001-02-23 17:55:21 +00002209 xmlXPathObjectPtr ret;
2210 int i;
2211
2212 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002213 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002214 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002215 ret = xmlXPathNewNodeSet(NULL);
2216 else {
2217 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
2218 for (i = 1; i < val->nodeNr; ++i)
2219 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2220 }
Owen Taylor3473f882001-02-23 17:55:21 +00002221
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002222 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002223}
2224
2225/**
2226 * xmlXPathWrapNodeSet:
2227 * @val: the NodePtr value
2228 *
2229 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2230 *
2231 * Returns the newly created object.
2232 */
2233xmlXPathObjectPtr
2234xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2235 xmlXPathObjectPtr ret;
2236
2237 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2238 if (ret == NULL) {
2239 xmlGenericError(xmlGenericErrorContext,
2240 "xmlXPathWrapNodeSet: out of memory\n");
2241 return(NULL);
2242 }
2243 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2244 ret->type = XPATH_NODESET;
2245 ret->nodesetval = val;
2246 return(ret);
2247}
2248
2249/**
2250 * xmlXPathFreeNodeSetList:
2251 * @obj: an existing NodeSetList object
2252 *
2253 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2254 * the list contrary to xmlXPathFreeObject().
2255 */
2256void
2257xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2258 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002259 xmlFree(obj);
2260}
2261
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002262/**
2263 * xmlXPathDifference:
2264 * @nodes1: a node-set
2265 * @nodes2: a node-set
2266 *
2267 * Implements the EXSLT - Sets difference() function:
2268 * node-set set:difference (node-set, node-set)
2269 *
2270 * Returns the difference between the two node sets, or nodes1 if
2271 * nodes2 is empty
2272 */
2273xmlNodeSetPtr
2274xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2275 xmlNodeSetPtr ret;
2276 int i, l1;
2277 xmlNodePtr cur;
2278
2279 if (xmlXPathNodeSetIsEmpty(nodes2))
2280 return(nodes1);
2281
2282 ret = xmlXPathNodeSetCreate(NULL);
2283 if (xmlXPathNodeSetIsEmpty(nodes1))
2284 return(ret);
2285
2286 l1 = xmlXPathNodeSetGetLength(nodes1);
2287
2288 for (i = 0; i < l1; i++) {
2289 cur = xmlXPathNodeSetItem(nodes1, i);
2290 if (!xmlXPathNodeSetContains(nodes2, cur))
2291 xmlXPathNodeSetAddUnique(ret, cur);
2292 }
2293 return(ret);
2294}
2295
2296/**
2297 * xmlXPathIntersection:
2298 * @nodes1: a node-set
2299 * @nodes2: a node-set
2300 *
2301 * Implements the EXSLT - Sets intersection() function:
2302 * node-set set:intersection (node-set, node-set)
2303 *
2304 * Returns a node set comprising the nodes that are within both the
2305 * node sets passed as arguments
2306 */
2307xmlNodeSetPtr
2308xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2309 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2310 int i, l1;
2311 xmlNodePtr cur;
2312
2313 if (xmlXPathNodeSetIsEmpty(nodes1))
2314 return(ret);
2315 if (xmlXPathNodeSetIsEmpty(nodes2))
2316 return(ret);
2317
2318 l1 = xmlXPathNodeSetGetLength(nodes1);
2319
2320 for (i = 0; i < l1; i++) {
2321 cur = xmlXPathNodeSetItem(nodes1, i);
2322 if (xmlXPathNodeSetContains(nodes2, cur))
2323 xmlXPathNodeSetAddUnique(ret, cur);
2324 }
2325 return(ret);
2326}
2327
2328/**
2329 * xmlXPathDistinctSorted:
2330 * @nodes: a node-set, sorted by document order
2331 *
2332 * Implements the EXSLT - Sets distinct() function:
2333 * node-set set:distinct (node-set)
2334 *
2335 * Returns a subset of the nodes contained in @nodes, or @nodes if
2336 * it is empty
2337 */
2338xmlNodeSetPtr
2339xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2340 xmlNodeSetPtr ret;
2341 xmlHashTablePtr hash;
2342 int i, l;
2343 xmlChar * strval;
2344 xmlNodePtr cur;
2345
2346 if (xmlXPathNodeSetIsEmpty(nodes))
2347 return(nodes);
2348
2349 ret = xmlXPathNodeSetCreate(NULL);
2350 l = xmlXPathNodeSetGetLength(nodes);
2351 hash = xmlHashCreate (l);
2352 for (i = 0; i < l; i++) {
2353 cur = xmlXPathNodeSetItem(nodes, i);
2354 strval = xmlXPathCastNodeToString(cur);
2355 if (xmlHashLookup(hash, strval) == NULL) {
2356 xmlHashAddEntry(hash, strval, strval);
2357 xmlXPathNodeSetAddUnique(ret, cur);
2358 } else {
2359 xmlFree(strval);
2360 }
2361 }
2362 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2363 return(ret);
2364}
2365
2366/**
2367 * xmlXPathDistinct:
2368 * @nodes: a node-set
2369 *
2370 * Implements the EXSLT - Sets distinct() function:
2371 * node-set set:distinct (node-set)
2372 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2373 * is called with the sorted node-set
2374 *
2375 * Returns a subset of the nodes contained in @nodes, or @nodes if
2376 * it is empty
2377 */
2378xmlNodeSetPtr
2379xmlXPathDistinct (xmlNodeSetPtr nodes) {
2380 if (xmlXPathNodeSetIsEmpty(nodes))
2381 return(nodes);
2382
2383 xmlXPathNodeSetSort(nodes);
2384 return(xmlXPathDistinctSorted(nodes));
2385}
2386
2387/**
2388 * xmlXPathHasSameNodes:
2389 * @nodes1: a node-set
2390 * @nodes2: a node-set
2391 *
2392 * Implements the EXSLT - Sets has-same-nodes function:
2393 * boolean set:has-same-node(node-set, node-set)
2394 *
2395 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2396 * otherwise
2397 */
2398int
2399xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2400 int i, l;
2401 xmlNodePtr cur;
2402
2403 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2404 xmlXPathNodeSetIsEmpty(nodes2))
2405 return(0);
2406
2407 l = xmlXPathNodeSetGetLength(nodes1);
2408 for (i = 0; i < l; i++) {
2409 cur = xmlXPathNodeSetItem(nodes1, i);
2410 if (xmlXPathNodeSetContains(nodes2, cur))
2411 return(1);
2412 }
2413 return(0);
2414}
2415
2416/**
2417 * xmlXPathNodeLeadingSorted:
2418 * @nodes: a node-set, sorted by document order
2419 * @node: a node
2420 *
2421 * Implements the EXSLT - Sets leading() function:
2422 * node-set set:leading (node-set, node-set)
2423 *
2424 * Returns the nodes in @nodes that precede @node in document order,
2425 * @nodes if @node is NULL or an empty node-set if @nodes
2426 * doesn't contain @node
2427 */
2428xmlNodeSetPtr
2429xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2430 int i, l;
2431 xmlNodePtr cur;
2432 xmlNodeSetPtr ret;
2433
2434 if (node == NULL)
2435 return(nodes);
2436
2437 ret = xmlXPathNodeSetCreate(NULL);
2438 if (xmlXPathNodeSetIsEmpty(nodes) ||
2439 (!xmlXPathNodeSetContains(nodes, node)))
2440 return(ret);
2441
2442 l = xmlXPathNodeSetGetLength(nodes);
2443 for (i = 0; i < l; i++) {
2444 cur = xmlXPathNodeSetItem(nodes, i);
2445 if (cur == node)
2446 break;
2447 xmlXPathNodeSetAddUnique(ret, cur);
2448 }
2449 return(ret);
2450}
2451
2452/**
2453 * xmlXPathNodeLeading:
2454 * @nodes: a node-set
2455 * @node: a node
2456 *
2457 * Implements the EXSLT - Sets leading() function:
2458 * node-set set:leading (node-set, node-set)
2459 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2460 * is called.
2461 *
2462 * Returns the nodes in @nodes that precede @node in document order,
2463 * @nodes if @node is NULL or an empty node-set if @nodes
2464 * doesn't contain @node
2465 */
2466xmlNodeSetPtr
2467xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2468 xmlXPathNodeSetSort(nodes);
2469 return(xmlXPathNodeLeadingSorted(nodes, node));
2470}
2471
2472/**
2473 * xmlXPathLeadingSorted:
2474 * @nodes1: a node-set, sorted by document order
2475 * @nodes2: a node-set, sorted by document order
2476 *
2477 * Implements the EXSLT - Sets leading() function:
2478 * node-set set:leading (node-set, node-set)
2479 *
2480 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2481 * in document order, @nodes1 if @nodes2 is NULL or empty or
2482 * an empty node-set if @nodes1 doesn't contain @nodes2
2483 */
2484xmlNodeSetPtr
2485xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2486 if (xmlXPathNodeSetIsEmpty(nodes2))
2487 return(nodes1);
2488 return(xmlXPathNodeLeadingSorted(nodes1,
2489 xmlXPathNodeSetItem(nodes2, 1)));
2490}
2491
2492/**
2493 * xmlXPathLeading:
2494 * @nodes1: a node-set
2495 * @nodes2: a node-set
2496 *
2497 * Implements the EXSLT - Sets leading() function:
2498 * node-set set:leading (node-set, node-set)
2499 * @nodes1 and @nodes2 are sorted by document order, then
2500 * #exslSetsLeadingSorted is called.
2501 *
2502 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2503 * in document order, @nodes1 if @nodes2 is NULL or empty or
2504 * an empty node-set if @nodes1 doesn't contain @nodes2
2505 */
2506xmlNodeSetPtr
2507xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2508 if (xmlXPathNodeSetIsEmpty(nodes2))
2509 return(nodes1);
2510 if (xmlXPathNodeSetIsEmpty(nodes1))
2511 return(xmlXPathNodeSetCreate(NULL));
2512 xmlXPathNodeSetSort(nodes1);
2513 xmlXPathNodeSetSort(nodes2);
2514 return(xmlXPathNodeLeadingSorted(nodes1,
2515 xmlXPathNodeSetItem(nodes2, 1)));
2516}
2517
2518/**
2519 * xmlXPathNodeTrailingSorted:
2520 * @nodes: a node-set, sorted by document order
2521 * @node: a node
2522 *
2523 * Implements the EXSLT - Sets trailing() function:
2524 * node-set set:trailing (node-set, node-set)
2525 *
2526 * Returns the nodes in @nodes that follow @node in document order,
2527 * @nodes if @node is NULL or an empty node-set if @nodes
2528 * doesn't contain @node
2529 */
2530xmlNodeSetPtr
2531xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2532 int i, l;
2533 xmlNodePtr cur;
2534 xmlNodeSetPtr ret;
2535
2536 if (node == NULL)
2537 return(nodes);
2538
2539 ret = xmlXPathNodeSetCreate(NULL);
2540 if (xmlXPathNodeSetIsEmpty(nodes) ||
2541 (!xmlXPathNodeSetContains(nodes, node)))
2542 return(ret);
2543
2544 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002545 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002546 cur = xmlXPathNodeSetItem(nodes, i);
2547 if (cur == node)
2548 break;
2549 xmlXPathNodeSetAddUnique(ret, cur);
2550 }
2551 return(ret);
2552}
2553
2554/**
2555 * xmlXPathNodeTrailing:
2556 * @nodes: a node-set
2557 * @node: a node
2558 *
2559 * Implements the EXSLT - Sets trailing() function:
2560 * node-set set:trailing (node-set, node-set)
2561 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2562 * is called.
2563 *
2564 * Returns the nodes in @nodes that follow @node in document order,
2565 * @nodes if @node is NULL or an empty node-set if @nodes
2566 * doesn't contain @node
2567 */
2568xmlNodeSetPtr
2569xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2570 xmlXPathNodeSetSort(nodes);
2571 return(xmlXPathNodeTrailingSorted(nodes, node));
2572}
2573
2574/**
2575 * xmlXPathTrailingSorted:
2576 * @nodes1: a node-set, sorted by document order
2577 * @nodes2: a node-set, sorted by document order
2578 *
2579 * Implements the EXSLT - Sets trailing() function:
2580 * node-set set:trailing (node-set, node-set)
2581 *
2582 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2583 * in document order, @nodes1 if @nodes2 is NULL or empty or
2584 * an empty node-set if @nodes1 doesn't contain @nodes2
2585 */
2586xmlNodeSetPtr
2587xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2588 if (xmlXPathNodeSetIsEmpty(nodes2))
2589 return(nodes1);
2590 return(xmlXPathNodeTrailingSorted(nodes1,
2591 xmlXPathNodeSetItem(nodes2, 0)));
2592}
2593
2594/**
2595 * xmlXPathTrailing:
2596 * @nodes1: a node-set
2597 * @nodes2: a node-set
2598 *
2599 * Implements the EXSLT - Sets trailing() function:
2600 * node-set set:trailing (node-set, node-set)
2601 * @nodes1 and @nodes2 are sorted by document order, then
2602 * #xmlXPathTrailingSorted is called.
2603 *
2604 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2605 * in document order, @nodes1 if @nodes2 is NULL or empty or
2606 * an empty node-set if @nodes1 doesn't contain @nodes2
2607 */
2608xmlNodeSetPtr
2609xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2610 if (xmlXPathNodeSetIsEmpty(nodes2))
2611 return(nodes1);
2612 if (xmlXPathNodeSetIsEmpty(nodes1))
2613 return(xmlXPathNodeSetCreate(NULL));
2614 xmlXPathNodeSetSort(nodes1);
2615 xmlXPathNodeSetSort(nodes2);
2616 return(xmlXPathNodeTrailingSorted(nodes1,
2617 xmlXPathNodeSetItem(nodes2, 0)));
2618}
2619
Owen Taylor3473f882001-02-23 17:55:21 +00002620/************************************************************************
2621 * *
2622 * Routines to handle extra functions *
2623 * *
2624 ************************************************************************/
2625
2626/**
2627 * xmlXPathRegisterFunc:
2628 * @ctxt: the XPath context
2629 * @name: the function name
2630 * @f: the function implementation or NULL
2631 *
2632 * Register a new function. If @f is NULL it unregisters the function
2633 *
2634 * Returns 0 in case of success, -1 in case of error
2635 */
2636int
2637xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2638 xmlXPathFunction f) {
2639 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2640}
2641
2642/**
2643 * xmlXPathRegisterFuncNS:
2644 * @ctxt: the XPath context
2645 * @name: the function name
2646 * @ns_uri: the function namespace URI
2647 * @f: the function implementation or NULL
2648 *
2649 * Register a new function. If @f is NULL it unregisters the function
2650 *
2651 * Returns 0 in case of success, -1 in case of error
2652 */
2653int
2654xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2655 const xmlChar *ns_uri, xmlXPathFunction f) {
2656 if (ctxt == NULL)
2657 return(-1);
2658 if (name == NULL)
2659 return(-1);
2660
2661 if (ctxt->funcHash == NULL)
2662 ctxt->funcHash = xmlHashCreate(0);
2663 if (ctxt->funcHash == NULL)
2664 return(-1);
2665 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2666}
2667
2668/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002669 * xmlXPathRegisterFuncLookup:
2670 * @ctxt: the XPath context
2671 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002672 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00002673 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002674 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00002675 */
2676void
2677xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2678 xmlXPathFuncLookupFunc f,
2679 void *funcCtxt) {
2680 if (ctxt == NULL)
2681 return;
2682 ctxt->funcLookupFunc = (void *) f;
2683 ctxt->funcLookupData = funcCtxt;
2684}
2685
2686/**
Owen Taylor3473f882001-02-23 17:55:21 +00002687 * xmlXPathFunctionLookup:
2688 * @ctxt: the XPath context
2689 * @name: the function name
2690 *
2691 * Search in the Function array of the context for the given
2692 * function.
2693 *
2694 * Returns the xmlXPathFunction or NULL if not found
2695 */
2696xmlXPathFunction
2697xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002698 if (ctxt == NULL)
2699 return (NULL);
2700
2701 if (ctxt->funcLookupFunc != NULL) {
2702 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002703 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002704
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002705 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002706 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002707 if (ret != NULL)
2708 return(ret);
2709 }
Owen Taylor3473f882001-02-23 17:55:21 +00002710 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2711}
2712
2713/**
2714 * xmlXPathFunctionLookupNS:
2715 * @ctxt: the XPath context
2716 * @name: the function name
2717 * @ns_uri: the function namespace URI
2718 *
2719 * Search in the Function array of the context for the given
2720 * function.
2721 *
2722 * Returns the xmlXPathFunction or NULL if not found
2723 */
2724xmlXPathFunction
2725xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2726 const xmlChar *ns_uri) {
2727 if (ctxt == NULL)
2728 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002729 if (name == NULL)
2730 return(NULL);
2731
Thomas Broyerba4ad322001-07-26 16:55:21 +00002732 if (ctxt->funcLookupFunc != NULL) {
2733 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002734 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002735
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002736 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002737 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002738 if (ret != NULL)
2739 return(ret);
2740 }
2741
2742 if (ctxt->funcHash == NULL)
2743 return(NULL);
2744
Owen Taylor3473f882001-02-23 17:55:21 +00002745 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2746}
2747
2748/**
2749 * xmlXPathRegisteredFuncsCleanup:
2750 * @ctxt: the XPath context
2751 *
2752 * Cleanup the XPath context data associated to registered functions
2753 */
2754void
2755xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2756 if (ctxt == NULL)
2757 return;
2758
2759 xmlHashFree(ctxt->funcHash, NULL);
2760 ctxt->funcHash = NULL;
2761}
2762
2763/************************************************************************
2764 * *
2765 * Routines to handle Variable *
2766 * *
2767 ************************************************************************/
2768
2769/**
2770 * xmlXPathRegisterVariable:
2771 * @ctxt: the XPath context
2772 * @name: the variable name
2773 * @value: the variable value or NULL
2774 *
2775 * Register a new variable value. If @value is NULL it unregisters
2776 * the variable
2777 *
2778 * Returns 0 in case of success, -1 in case of error
2779 */
2780int
2781xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2782 xmlXPathObjectPtr value) {
2783 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2784}
2785
2786/**
2787 * xmlXPathRegisterVariableNS:
2788 * @ctxt: the XPath context
2789 * @name: the variable name
2790 * @ns_uri: the variable namespace URI
2791 * @value: the variable value or NULL
2792 *
2793 * Register a new variable value. If @value is NULL it unregisters
2794 * the variable
2795 *
2796 * Returns 0 in case of success, -1 in case of error
2797 */
2798int
2799xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2800 const xmlChar *ns_uri,
2801 xmlXPathObjectPtr value) {
2802 if (ctxt == NULL)
2803 return(-1);
2804 if (name == NULL)
2805 return(-1);
2806
2807 if (ctxt->varHash == NULL)
2808 ctxt->varHash = xmlHashCreate(0);
2809 if (ctxt->varHash == NULL)
2810 return(-1);
2811 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2812 (void *) value,
2813 (xmlHashDeallocator)xmlXPathFreeObject));
2814}
2815
2816/**
2817 * xmlXPathRegisterVariableLookup:
2818 * @ctxt: the XPath context
2819 * @f: the lookup function
2820 * @data: the lookup data
2821 *
2822 * register an external mechanism to do variable lookup
2823 */
2824void
2825xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2826 xmlXPathVariableLookupFunc f, void *data) {
2827 if (ctxt == NULL)
2828 return;
2829 ctxt->varLookupFunc = (void *) f;
2830 ctxt->varLookupData = data;
2831}
2832
2833/**
2834 * xmlXPathVariableLookup:
2835 * @ctxt: the XPath context
2836 * @name: the variable name
2837 *
2838 * Search in the Variable array of the context for the given
2839 * variable value.
2840 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002841 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002842 */
2843xmlXPathObjectPtr
2844xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2845 if (ctxt == NULL)
2846 return(NULL);
2847
2848 if (ctxt->varLookupFunc != NULL) {
2849 xmlXPathObjectPtr ret;
2850
2851 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2852 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00002853 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002854 }
2855 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
2856}
2857
2858/**
2859 * xmlXPathVariableLookupNS:
2860 * @ctxt: the XPath context
2861 * @name: the variable name
2862 * @ns_uri: the variable namespace URI
2863 *
2864 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00002865 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00002866 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002867 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002868 */
2869xmlXPathObjectPtr
2870xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2871 const xmlChar *ns_uri) {
2872 if (ctxt == NULL)
2873 return(NULL);
2874
2875 if (ctxt->varLookupFunc != NULL) {
2876 xmlXPathObjectPtr ret;
2877
2878 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2879 (ctxt->varLookupData, name, ns_uri);
2880 if (ret != NULL) return(ret);
2881 }
2882
2883 if (ctxt->varHash == NULL)
2884 return(NULL);
2885 if (name == NULL)
2886 return(NULL);
2887
Daniel Veillard8c357d52001-07-03 23:43:33 +00002888 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
2889 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00002890}
2891
2892/**
2893 * xmlXPathRegisteredVariablesCleanup:
2894 * @ctxt: the XPath context
2895 *
2896 * Cleanup the XPath context data associated to registered variables
2897 */
2898void
2899xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
2900 if (ctxt == NULL)
2901 return;
2902
Daniel Veillard76d66f42001-05-16 21:05:17 +00002903 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00002904 ctxt->varHash = NULL;
2905}
2906
2907/**
2908 * xmlXPathRegisterNs:
2909 * @ctxt: the XPath context
2910 * @prefix: the namespace prefix
2911 * @ns_uri: the namespace name
2912 *
2913 * Register a new namespace. If @ns_uri is NULL it unregisters
2914 * the namespace
2915 *
2916 * Returns 0 in case of success, -1 in case of error
2917 */
2918int
2919xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
2920 const xmlChar *ns_uri) {
2921 if (ctxt == NULL)
2922 return(-1);
2923 if (prefix == NULL)
2924 return(-1);
2925
2926 if (ctxt->nsHash == NULL)
2927 ctxt->nsHash = xmlHashCreate(10);
2928 if (ctxt->nsHash == NULL)
2929 return(-1);
Daniel Veillard42766c02002-08-22 20:52:17 +00002930 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00002931 (xmlHashDeallocator)xmlFree));
2932}
2933
2934/**
2935 * xmlXPathNsLookup:
2936 * @ctxt: the XPath context
2937 * @prefix: the namespace prefix value
2938 *
2939 * Search in the namespace declaration array of the context for the given
2940 * namespace name associated to the given prefix
2941 *
2942 * Returns the value or NULL if not found
2943 */
2944const xmlChar *
2945xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
2946 if (ctxt == NULL)
2947 return(NULL);
2948 if (prefix == NULL)
2949 return(NULL);
2950
2951#ifdef XML_XML_NAMESPACE
2952 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
2953 return(XML_XML_NAMESPACE);
2954#endif
2955
Daniel Veillardc8f620b2001-04-30 20:31:33 +00002956 if (ctxt->namespaces != NULL) {
2957 int i;
2958
2959 for (i = 0;i < ctxt->nsNr;i++) {
2960 if ((ctxt->namespaces[i] != NULL) &&
2961 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
2962 return(ctxt->namespaces[i]->href);
2963 }
2964 }
Owen Taylor3473f882001-02-23 17:55:21 +00002965
2966 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
2967}
2968
2969/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002970 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00002971 * @ctxt: the XPath context
2972 *
2973 * Cleanup the XPath context data associated to registered variables
2974 */
2975void
2976xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
2977 if (ctxt == NULL)
2978 return;
2979
Daniel Veillard42766c02002-08-22 20:52:17 +00002980 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00002981 ctxt->nsHash = NULL;
2982}
2983
2984/************************************************************************
2985 * *
2986 * Routines to handle Values *
2987 * *
2988 ************************************************************************/
2989
2990/* Allocations are terrible, one need to optimize all this !!! */
2991
2992/**
2993 * xmlXPathNewFloat:
2994 * @val: the double value
2995 *
2996 * Create a new xmlXPathObjectPtr of type double and of value @val
2997 *
2998 * Returns the newly created object.
2999 */
3000xmlXPathObjectPtr
3001xmlXPathNewFloat(double val) {
3002 xmlXPathObjectPtr ret;
3003
3004 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3005 if (ret == NULL) {
3006 xmlGenericError(xmlGenericErrorContext,
3007 "xmlXPathNewFloat: out of memory\n");
3008 return(NULL);
3009 }
3010 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3011 ret->type = XPATH_NUMBER;
3012 ret->floatval = val;
3013 return(ret);
3014}
3015
3016/**
3017 * xmlXPathNewBoolean:
3018 * @val: the boolean value
3019 *
3020 * Create a new xmlXPathObjectPtr of type boolean and of value @val
3021 *
3022 * Returns the newly created object.
3023 */
3024xmlXPathObjectPtr
3025xmlXPathNewBoolean(int val) {
3026 xmlXPathObjectPtr ret;
3027
3028 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3029 if (ret == NULL) {
3030 xmlGenericError(xmlGenericErrorContext,
3031 "xmlXPathNewBoolean: out of memory\n");
3032 return(NULL);
3033 }
3034 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3035 ret->type = XPATH_BOOLEAN;
3036 ret->boolval = (val != 0);
3037 return(ret);
3038}
3039
3040/**
3041 * xmlXPathNewString:
3042 * @val: the xmlChar * value
3043 *
3044 * Create a new xmlXPathObjectPtr of type string and of value @val
3045 *
3046 * Returns the newly created object.
3047 */
3048xmlXPathObjectPtr
3049xmlXPathNewString(const xmlChar *val) {
3050 xmlXPathObjectPtr ret;
3051
3052 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3053 if (ret == NULL) {
3054 xmlGenericError(xmlGenericErrorContext,
3055 "xmlXPathNewString: out of memory\n");
3056 return(NULL);
3057 }
3058 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3059 ret->type = XPATH_STRING;
3060 if (val != NULL)
3061 ret->stringval = xmlStrdup(val);
3062 else
3063 ret->stringval = xmlStrdup((const xmlChar *)"");
3064 return(ret);
3065}
3066
3067/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003068 * xmlXPathWrapString:
3069 * @val: the xmlChar * value
3070 *
3071 * Wraps the @val string into an XPath object.
3072 *
3073 * Returns the newly created object.
3074 */
3075xmlXPathObjectPtr
3076xmlXPathWrapString (xmlChar *val) {
3077 xmlXPathObjectPtr ret;
3078
3079 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3080 if (ret == NULL) {
3081 xmlGenericError(xmlGenericErrorContext,
3082 "xmlXPathWrapString: out of memory\n");
3083 return(NULL);
3084 }
3085 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3086 ret->type = XPATH_STRING;
3087 ret->stringval = val;
3088 return(ret);
3089}
3090
3091/**
Owen Taylor3473f882001-02-23 17:55:21 +00003092 * xmlXPathNewCString:
3093 * @val: the char * value
3094 *
3095 * Create a new xmlXPathObjectPtr of type string and of value @val
3096 *
3097 * Returns the newly created object.
3098 */
3099xmlXPathObjectPtr
3100xmlXPathNewCString(const char *val) {
3101 xmlXPathObjectPtr ret;
3102
3103 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3104 if (ret == NULL) {
3105 xmlGenericError(xmlGenericErrorContext,
3106 "xmlXPathNewCString: out of memory\n");
3107 return(NULL);
3108 }
3109 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3110 ret->type = XPATH_STRING;
3111 ret->stringval = xmlStrdup(BAD_CAST val);
3112 return(ret);
3113}
3114
3115/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003116 * xmlXPathWrapCString:
3117 * @val: the char * value
3118 *
3119 * Wraps a string into an XPath object.
3120 *
3121 * Returns the newly created object.
3122 */
3123xmlXPathObjectPtr
3124xmlXPathWrapCString (char * val) {
3125 return(xmlXPathWrapString((xmlChar *)(val)));
3126}
3127
3128/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003129 * xmlXPathWrapExternal:
3130 * @val: the user data
3131 *
3132 * Wraps the @val data into an XPath object.
3133 *
3134 * Returns the newly created object.
3135 */
3136xmlXPathObjectPtr
3137xmlXPathWrapExternal (void *val) {
3138 xmlXPathObjectPtr ret;
3139
3140 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3141 if (ret == NULL) {
3142 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003143 "xmlXPathWrapExternal: out of memory\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003144 return(NULL);
3145 }
3146 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3147 ret->type = XPATH_USERS;
3148 ret->user = val;
3149 return(ret);
3150}
3151
3152/**
Owen Taylor3473f882001-02-23 17:55:21 +00003153 * xmlXPathObjectCopy:
3154 * @val: the original object
3155 *
3156 * allocate a new copy of a given object
3157 *
3158 * Returns the newly created object.
3159 */
3160xmlXPathObjectPtr
3161xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3162 xmlXPathObjectPtr ret;
3163
3164 if (val == NULL)
3165 return(NULL);
3166
3167 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3168 if (ret == NULL) {
3169 xmlGenericError(xmlGenericErrorContext,
3170 "xmlXPathObjectCopy: out of memory\n");
3171 return(NULL);
3172 }
3173 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3174 switch (val->type) {
3175 case XPATH_BOOLEAN:
3176 case XPATH_NUMBER:
3177 case XPATH_POINT:
3178 case XPATH_RANGE:
3179 break;
3180 case XPATH_STRING:
3181 ret->stringval = xmlStrdup(val->stringval);
3182 break;
3183 case XPATH_XSLT_TREE:
3184 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003185 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003186 xmlNodePtr cur, tmp;
3187 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003188
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003189 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00003190 top = xmlNewDoc(NULL);
3191 top->name = (char *)
3192 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003193 ret->user = top;
3194 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003195 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003196 cur = val->nodesetval->nodeTab[0]->children;
3197 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003198 tmp = xmlDocCopyNode(cur, top, 1);
3199 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003200 cur = cur->next;
3201 }
3202 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003203 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003204 } else
Owen Taylor3473f882001-02-23 17:55:21 +00003205 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003206 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00003207 break;
3208 case XPATH_NODESET:
3209 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003210 /* Do not deallocate the copied tree value */
3211 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003212 break;
3213 case XPATH_LOCATIONSET:
3214#ifdef LIBXML_XPTR_ENABLED
3215 {
3216 xmlLocationSetPtr loc = val->user;
3217 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3218 break;
3219 }
3220#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00003221 case XPATH_USERS:
3222 ret->user = val->user;
3223 break;
3224 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00003225 xmlGenericError(xmlGenericErrorContext,
3226 "xmlXPathObjectCopy: unsupported type %d\n",
3227 val->type);
3228 break;
3229 }
3230 return(ret);
3231}
3232
3233/**
3234 * xmlXPathFreeObject:
3235 * @obj: the object to free
3236 *
3237 * Free up an xmlXPathObjectPtr object.
3238 */
3239void
3240xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3241 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003242 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00003243 if (obj->boolval) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003244 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003245 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00003246 xmlFreeNodeList((xmlNodePtr) obj->user);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003247 } else if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00003248 xmlXPathFreeValueTree(obj->nodesetval);
3249 } else {
3250 if (obj->nodesetval != NULL)
3251 xmlXPathFreeNodeSet(obj->nodesetval);
3252 }
Owen Taylor3473f882001-02-23 17:55:21 +00003253#ifdef LIBXML_XPTR_ENABLED
3254 } else if (obj->type == XPATH_LOCATIONSET) {
3255 if (obj->user != NULL)
3256 xmlXPtrFreeLocationSet(obj->user);
3257#endif
3258 } else if (obj->type == XPATH_STRING) {
3259 if (obj->stringval != NULL)
3260 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00003261 }
3262
Owen Taylor3473f882001-02-23 17:55:21 +00003263 xmlFree(obj);
3264}
3265
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003266
3267/************************************************************************
3268 * *
3269 * Type Casting Routines *
3270 * *
3271 ************************************************************************/
3272
3273/**
3274 * xmlXPathCastBooleanToString:
3275 * @val: a boolean
3276 *
3277 * Converts a boolean to its string value.
3278 *
3279 * Returns a newly allocated string.
3280 */
3281xmlChar *
3282xmlXPathCastBooleanToString (int val) {
3283 xmlChar *ret;
3284 if (val)
3285 ret = xmlStrdup((const xmlChar *) "true");
3286 else
3287 ret = xmlStrdup((const xmlChar *) "false");
3288 return(ret);
3289}
3290
3291/**
3292 * xmlXPathCastNumberToString:
3293 * @val: a number
3294 *
3295 * Converts a number to its string value.
3296 *
3297 * Returns a newly allocated string.
3298 */
3299xmlChar *
3300xmlXPathCastNumberToString (double val) {
3301 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00003302 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003303 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003304 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003305 break;
3306 case -1:
3307 ret = xmlStrdup((const xmlChar *) "-Infinity");
3308 break;
3309 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003310 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003311 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00003312 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
3313 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003314 } else {
3315 /* could be improved */
3316 char buf[100];
3317 xmlXPathFormatNumber(val, buf, 100);
3318 ret = xmlStrdup((const xmlChar *) buf);
3319 }
3320 }
3321 return(ret);
3322}
3323
3324/**
3325 * xmlXPathCastNodeToString:
3326 * @node: a node
3327 *
3328 * Converts a node to its string value.
3329 *
3330 * Returns a newly allocated string.
3331 */
3332xmlChar *
3333xmlXPathCastNodeToString (xmlNodePtr node) {
3334 return(xmlNodeGetContent(node));
3335}
3336
3337/**
3338 * xmlXPathCastNodeSetToString:
3339 * @ns: a node-set
3340 *
3341 * Converts a node-set to its string value.
3342 *
3343 * Returns a newly allocated string.
3344 */
3345xmlChar *
3346xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3347 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3348 return(xmlStrdup((const xmlChar *) ""));
3349
3350 xmlXPathNodeSetSort(ns);
3351 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3352}
3353
3354/**
3355 * xmlXPathCastToString:
3356 * @val: an XPath object
3357 *
3358 * Converts an existing object to its string() equivalent
3359 *
3360 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003361 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003362 * string object).
3363 */
3364xmlChar *
3365xmlXPathCastToString(xmlXPathObjectPtr val) {
3366 xmlChar *ret = NULL;
3367
3368 if (val == NULL)
3369 return(xmlStrdup((const xmlChar *) ""));
3370 switch (val->type) {
3371 case XPATH_UNDEFINED:
3372#ifdef DEBUG_EXPR
3373 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3374#endif
3375 ret = xmlStrdup((const xmlChar *) "");
3376 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003377 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003378 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003379 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3380 break;
3381 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00003382 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003383 case XPATH_BOOLEAN:
3384 ret = xmlXPathCastBooleanToString(val->boolval);
3385 break;
3386 case XPATH_NUMBER: {
3387 ret = xmlXPathCastNumberToString(val->floatval);
3388 break;
3389 }
3390 case XPATH_USERS:
3391 case XPATH_POINT:
3392 case XPATH_RANGE:
3393 case XPATH_LOCATIONSET:
3394 TODO
3395 ret = xmlStrdup((const xmlChar *) "");
3396 break;
3397 }
3398 return(ret);
3399}
3400
3401/**
3402 * xmlXPathConvertString:
3403 * @val: an XPath object
3404 *
3405 * Converts an existing object to its string() equivalent
3406 *
3407 * Returns the new object, the old one is freed (or the operation
3408 * is done directly on @val)
3409 */
3410xmlXPathObjectPtr
3411xmlXPathConvertString(xmlXPathObjectPtr val) {
3412 xmlChar *res = NULL;
3413
3414 if (val == NULL)
3415 return(xmlXPathNewCString(""));
3416
3417 switch (val->type) {
3418 case XPATH_UNDEFINED:
3419#ifdef DEBUG_EXPR
3420 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3421#endif
3422 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003423 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003424 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003425 res = xmlXPathCastNodeSetToString(val->nodesetval);
3426 break;
3427 case XPATH_STRING:
3428 return(val);
3429 case XPATH_BOOLEAN:
3430 res = xmlXPathCastBooleanToString(val->boolval);
3431 break;
3432 case XPATH_NUMBER:
3433 res = xmlXPathCastNumberToString(val->floatval);
3434 break;
3435 case XPATH_USERS:
3436 case XPATH_POINT:
3437 case XPATH_RANGE:
3438 case XPATH_LOCATIONSET:
3439 TODO;
3440 break;
3441 }
3442 xmlXPathFreeObject(val);
3443 if (res == NULL)
3444 return(xmlXPathNewCString(""));
3445 return(xmlXPathWrapString(res));
3446}
3447
3448/**
3449 * xmlXPathCastBooleanToNumber:
3450 * @val: a boolean
3451 *
3452 * Converts a boolean to its number value
3453 *
3454 * Returns the number value
3455 */
3456double
3457xmlXPathCastBooleanToNumber(int val) {
3458 if (val)
3459 return(1.0);
3460 return(0.0);
3461}
3462
3463/**
3464 * xmlXPathCastStringToNumber:
3465 * @val: a string
3466 *
3467 * Converts a string to its number value
3468 *
3469 * Returns the number value
3470 */
3471double
3472xmlXPathCastStringToNumber(const xmlChar * val) {
3473 return(xmlXPathStringEvalNumber(val));
3474}
3475
3476/**
3477 * xmlXPathCastNodeToNumber:
3478 * @node: a node
3479 *
3480 * Converts a node to its number value
3481 *
3482 * Returns the number value
3483 */
3484double
3485xmlXPathCastNodeToNumber (xmlNodePtr node) {
3486 xmlChar *strval;
3487 double ret;
3488
3489 if (node == NULL)
3490 return(xmlXPathNAN);
3491 strval = xmlXPathCastNodeToString(node);
3492 if (strval == NULL)
3493 return(xmlXPathNAN);
3494 ret = xmlXPathCastStringToNumber(strval);
3495 xmlFree(strval);
3496
3497 return(ret);
3498}
3499
3500/**
3501 * xmlXPathCastNodeSetToNumber:
3502 * @ns: a node-set
3503 *
3504 * Converts a node-set to its number value
3505 *
3506 * Returns the number value
3507 */
3508double
3509xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3510 xmlChar *str;
3511 double ret;
3512
3513 if (ns == NULL)
3514 return(xmlXPathNAN);
3515 str = xmlXPathCastNodeSetToString(ns);
3516 ret = xmlXPathCastStringToNumber(str);
3517 xmlFree(str);
3518 return(ret);
3519}
3520
3521/**
3522 * xmlXPathCastToNumber:
3523 * @val: an XPath object
3524 *
3525 * Converts an XPath object to its number value
3526 *
3527 * Returns the number value
3528 */
3529double
3530xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3531 double ret = 0.0;
3532
3533 if (val == NULL)
3534 return(xmlXPathNAN);
3535 switch (val->type) {
3536 case XPATH_UNDEFINED:
3537#ifdef DEGUB_EXPR
3538 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3539#endif
3540 ret = xmlXPathNAN;
3541 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003542 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003543 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003544 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3545 break;
3546 case XPATH_STRING:
3547 ret = xmlXPathCastStringToNumber(val->stringval);
3548 break;
3549 case XPATH_NUMBER:
3550 ret = val->floatval;
3551 break;
3552 case XPATH_BOOLEAN:
3553 ret = xmlXPathCastBooleanToNumber(val->boolval);
3554 break;
3555 case XPATH_USERS:
3556 case XPATH_POINT:
3557 case XPATH_RANGE:
3558 case XPATH_LOCATIONSET:
3559 TODO;
3560 ret = xmlXPathNAN;
3561 break;
3562 }
3563 return(ret);
3564}
3565
3566/**
3567 * xmlXPathConvertNumber:
3568 * @val: an XPath object
3569 *
3570 * Converts an existing object to its number() equivalent
3571 *
3572 * Returns the new object, the old one is freed (or the operation
3573 * is done directly on @val)
3574 */
3575xmlXPathObjectPtr
3576xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3577 xmlXPathObjectPtr ret;
3578
3579 if (val == NULL)
3580 return(xmlXPathNewFloat(0.0));
3581 if (val->type == XPATH_NUMBER)
3582 return(val);
3583 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3584 xmlXPathFreeObject(val);
3585 return(ret);
3586}
3587
3588/**
3589 * xmlXPathCastNumberToBoolean:
3590 * @val: a number
3591 *
3592 * Converts a number to its boolean value
3593 *
3594 * Returns the boolean value
3595 */
3596int
3597xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003598 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003599 return(0);
3600 return(1);
3601}
3602
3603/**
3604 * xmlXPathCastStringToBoolean:
3605 * @val: a string
3606 *
3607 * Converts a string to its boolean value
3608 *
3609 * Returns the boolean value
3610 */
3611int
3612xmlXPathCastStringToBoolean (const xmlChar *val) {
3613 if ((val == NULL) || (xmlStrlen(val) == 0))
3614 return(0);
3615 return(1);
3616}
3617
3618/**
3619 * xmlXPathCastNodeSetToBoolean:
3620 * @ns: a node-set
3621 *
3622 * Converts a node-set to its boolean value
3623 *
3624 * Returns the boolean value
3625 */
3626int
3627xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3628 if ((ns == NULL) || (ns->nodeNr == 0))
3629 return(0);
3630 return(1);
3631}
3632
3633/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003634 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003635 * @val: an XPath object
3636 *
3637 * Converts an XPath object to its boolean value
3638 *
3639 * Returns the boolean value
3640 */
3641int
3642xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3643 int ret = 0;
3644
3645 if (val == NULL)
3646 return(0);
3647 switch (val->type) {
3648 case XPATH_UNDEFINED:
3649#ifdef DEBUG_EXPR
3650 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3651#endif
3652 ret = 0;
3653 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003654 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003655 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003656 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3657 break;
3658 case XPATH_STRING:
3659 ret = xmlXPathCastStringToBoolean(val->stringval);
3660 break;
3661 case XPATH_NUMBER:
3662 ret = xmlXPathCastNumberToBoolean(val->floatval);
3663 break;
3664 case XPATH_BOOLEAN:
3665 ret = val->boolval;
3666 break;
3667 case XPATH_USERS:
3668 case XPATH_POINT:
3669 case XPATH_RANGE:
3670 case XPATH_LOCATIONSET:
3671 TODO;
3672 ret = 0;
3673 break;
3674 }
3675 return(ret);
3676}
3677
3678
3679/**
3680 * xmlXPathConvertBoolean:
3681 * @val: an XPath object
3682 *
3683 * Converts an existing object to its boolean() equivalent
3684 *
3685 * Returns the new object, the old one is freed (or the operation
3686 * is done directly on @val)
3687 */
3688xmlXPathObjectPtr
3689xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3690 xmlXPathObjectPtr ret;
3691
3692 if (val == NULL)
3693 return(xmlXPathNewBoolean(0));
3694 if (val->type == XPATH_BOOLEAN)
3695 return(val);
3696 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3697 xmlXPathFreeObject(val);
3698 return(ret);
3699}
3700
Owen Taylor3473f882001-02-23 17:55:21 +00003701/************************************************************************
3702 * *
3703 * Routines to handle XPath contexts *
3704 * *
3705 ************************************************************************/
3706
3707/**
3708 * xmlXPathNewContext:
3709 * @doc: the XML document
3710 *
3711 * Create a new xmlXPathContext
3712 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00003713 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00003714 */
3715xmlXPathContextPtr
3716xmlXPathNewContext(xmlDocPtr doc) {
3717 xmlXPathContextPtr ret;
3718
3719 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3720 if (ret == NULL) {
3721 xmlGenericError(xmlGenericErrorContext,
3722 "xmlXPathNewContext: out of memory\n");
3723 return(NULL);
3724 }
3725 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3726 ret->doc = doc;
3727 ret->node = NULL;
3728
3729 ret->varHash = NULL;
3730
3731 ret->nb_types = 0;
3732 ret->max_types = 0;
3733 ret->types = NULL;
3734
3735 ret->funcHash = xmlHashCreate(0);
3736
3737 ret->nb_axis = 0;
3738 ret->max_axis = 0;
3739 ret->axis = NULL;
3740
3741 ret->nsHash = NULL;
3742 ret->user = NULL;
3743
3744 ret->contextSize = -1;
3745 ret->proximityPosition = -1;
3746
3747 xmlXPathRegisterAllFunctions(ret);
3748
3749 return(ret);
3750}
3751
3752/**
3753 * xmlXPathFreeContext:
3754 * @ctxt: the context to free
3755 *
3756 * Free up an xmlXPathContext
3757 */
3758void
3759xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3760 xmlXPathRegisteredNsCleanup(ctxt);
3761 xmlXPathRegisteredFuncsCleanup(ctxt);
3762 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003763 xmlFree(ctxt);
3764}
3765
3766/************************************************************************
3767 * *
3768 * Routines to handle XPath parser contexts *
3769 * *
3770 ************************************************************************/
3771
3772#define CHECK_CTXT(ctxt) \
3773 if (ctxt == NULL) { \
3774 xmlGenericError(xmlGenericErrorContext, \
3775 "%s:%d Internal error: ctxt == NULL\n", \
3776 __FILE__, __LINE__); \
3777 } \
3778
3779
3780#define CHECK_CONTEXT(ctxt) \
3781 if (ctxt == NULL) { \
3782 xmlGenericError(xmlGenericErrorContext, \
3783 "%s:%d Internal error: no context\n", \
3784 __FILE__, __LINE__); \
3785 } \
3786 else if (ctxt->doc == NULL) { \
3787 xmlGenericError(xmlGenericErrorContext, \
3788 "%s:%d Internal error: no document\n", \
3789 __FILE__, __LINE__); \
3790 } \
3791 else if (ctxt->doc->children == NULL) { \
3792 xmlGenericError(xmlGenericErrorContext, \
3793 "%s:%d Internal error: document without root\n", \
3794 __FILE__, __LINE__); \
3795 } \
3796
3797
3798/**
3799 * xmlXPathNewParserContext:
3800 * @str: the XPath expression
3801 * @ctxt: the XPath context
3802 *
3803 * Create a new xmlXPathParserContext
3804 *
3805 * Returns the xmlXPathParserContext just allocated.
3806 */
3807xmlXPathParserContextPtr
3808xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3809 xmlXPathParserContextPtr ret;
3810
3811 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3812 if (ret == NULL) {
3813 xmlGenericError(xmlGenericErrorContext,
3814 "xmlXPathNewParserContext: out of memory\n");
3815 return(NULL);
3816 }
3817 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3818 ret->cur = ret->base = str;
3819 ret->context = ctxt;
3820
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003821 ret->comp = xmlXPathNewCompExpr();
3822 if (ret->comp == NULL) {
3823 xmlFree(ret->valueTab);
3824 xmlFree(ret);
3825 return(NULL);
3826 }
3827
3828 return(ret);
3829}
3830
3831/**
3832 * xmlXPathCompParserContext:
3833 * @comp: the XPath compiled expression
3834 * @ctxt: the XPath context
3835 *
3836 * Create a new xmlXPathParserContext when processing a compiled expression
3837 *
3838 * Returns the xmlXPathParserContext just allocated.
3839 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003840static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003841xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3842 xmlXPathParserContextPtr ret;
3843
3844 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3845 if (ret == NULL) {
3846 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003847 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003848 return(NULL);
3849 }
3850 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3851
Owen Taylor3473f882001-02-23 17:55:21 +00003852 /* Allocate the value stack */
3853 ret->valueTab = (xmlXPathObjectPtr *)
3854 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003855 if (ret->valueTab == NULL) {
3856 xmlFree(ret);
3857 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003858 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003859 return(NULL);
3860 }
Owen Taylor3473f882001-02-23 17:55:21 +00003861 ret->valueNr = 0;
3862 ret->valueMax = 10;
3863 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003864
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00003865 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003866 ret->comp = comp;
3867
Owen Taylor3473f882001-02-23 17:55:21 +00003868 return(ret);
3869}
3870
3871/**
3872 * xmlXPathFreeParserContext:
3873 * @ctxt: the context to free
3874 *
3875 * Free up an xmlXPathParserContext
3876 */
3877void
3878xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
3879 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003880 xmlFree(ctxt->valueTab);
3881 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003882 if (ctxt->comp)
3883 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00003884 xmlFree(ctxt);
3885}
3886
3887/************************************************************************
3888 * *
3889 * The implicit core function library *
3890 * *
3891 ************************************************************************/
3892
Owen Taylor3473f882001-02-23 17:55:21 +00003893/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00003894 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00003895 * @node: a node pointer
3896 *
3897 * Function computing the beginning of the string value of the node,
3898 * used to speed up comparisons
3899 *
3900 * Returns an int usable as a hash
3901 */
3902static unsigned int
3903xmlXPathNodeValHash(xmlNodePtr node) {
3904 int len = 2;
3905 const xmlChar * string = NULL;
3906 xmlNodePtr tmp = NULL;
3907 unsigned int ret = 0;
3908
3909 if (node == NULL)
3910 return(0);
3911
Daniel Veillard9adc0462003-03-24 18:39:54 +00003912 if (node->type == XML_DOCUMENT_NODE) {
3913 tmp = xmlDocGetRootElement((xmlDocPtr) node);
3914 if (tmp == NULL)
3915 node = node->children;
3916 else
3917 node = tmp;
3918
3919 if (node == NULL)
3920 return(0);
3921 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003922
3923 switch (node->type) {
3924 case XML_COMMENT_NODE:
3925 case XML_PI_NODE:
3926 case XML_CDATA_SECTION_NODE:
3927 case XML_TEXT_NODE:
3928 string = node->content;
3929 if (string == NULL)
3930 return(0);
3931 if (string[0] == 0)
3932 return(0);
3933 return(((unsigned int) string[0]) +
3934 (((unsigned int) string[1]) << 8));
3935 case XML_NAMESPACE_DECL:
3936 string = ((xmlNsPtr)node)->href;
3937 if (string == NULL)
3938 return(0);
3939 if (string[0] == 0)
3940 return(0);
3941 return(((unsigned int) string[0]) +
3942 (((unsigned int) string[1]) << 8));
3943 case XML_ATTRIBUTE_NODE:
3944 tmp = ((xmlAttrPtr) node)->children;
3945 break;
3946 case XML_ELEMENT_NODE:
3947 tmp = node->children;
3948 break;
3949 default:
3950 return(0);
3951 }
3952 while (tmp != NULL) {
3953 switch (tmp->type) {
3954 case XML_COMMENT_NODE:
3955 case XML_PI_NODE:
3956 case XML_CDATA_SECTION_NODE:
3957 case XML_TEXT_NODE:
3958 string = tmp->content;
3959 break;
3960 case XML_NAMESPACE_DECL:
3961 string = ((xmlNsPtr)tmp)->href;
3962 break;
3963 default:
3964 break;
3965 }
3966 if ((string != NULL) && (string[0] != 0)) {
3967 if (string[0] == 0)
3968 return(0);
3969 if (len == 1) {
3970 return(ret + (((unsigned int) string[0]) << 8));
3971 }
3972 if (string[1] == 0) {
3973 len = 1;
3974 ret = (unsigned int) string[0];
3975 } else {
3976 return(((unsigned int) string[0]) +
3977 (((unsigned int) string[1]) << 8));
3978 }
3979 }
3980 /*
3981 * Skip to next node
3982 */
3983 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
3984 if (tmp->children->type != XML_ENTITY_DECL) {
3985 tmp = tmp->children;
3986 continue;
3987 }
3988 }
3989 if (tmp == node)
3990 break;
3991
3992 if (tmp->next != NULL) {
3993 tmp = tmp->next;
3994 continue;
3995 }
3996
3997 do {
3998 tmp = tmp->parent;
3999 if (tmp == NULL)
4000 break;
4001 if (tmp == node) {
4002 tmp = NULL;
4003 break;
4004 }
4005 if (tmp->next != NULL) {
4006 tmp = tmp->next;
4007 break;
4008 }
4009 } while (tmp != NULL);
4010 }
4011 return(ret);
4012}
4013
4014/**
4015 * xmlXPathStringHash:
4016 * @string: a string
4017 *
4018 * Function computing the beginning of the string value of the node,
4019 * used to speed up comparisons
4020 *
4021 * Returns an int usable as a hash
4022 */
4023static unsigned int
4024xmlXPathStringHash(const xmlChar * string) {
4025 if (string == NULL)
4026 return((unsigned int) 0);
4027 if (string[0] == 0)
4028 return(0);
4029 return(((unsigned int) string[0]) +
4030 (((unsigned int) string[1]) << 8));
4031}
4032
4033/**
Owen Taylor3473f882001-02-23 17:55:21 +00004034 * xmlXPathCompareNodeSetFloat:
4035 * @ctxt: the XPath Parser context
4036 * @inf: less than (1) or greater than (0)
4037 * @strict: is the comparison strict
4038 * @arg: the node set
4039 * @f: the value
4040 *
4041 * Implement the compare operation between a nodeset and a number
4042 * @ns < @val (1, 1, ...
4043 * @ns <= @val (1, 0, ...
4044 * @ns > @val (0, 1, ...
4045 * @ns >= @val (0, 0, ...
4046 *
4047 * If one object to be compared is a node-set and the other is a number,
4048 * then the comparison will be true if and only if there is a node in the
4049 * node-set such that the result of performing the comparison on the number
4050 * to be compared and on the result of converting the string-value of that
4051 * node to a number using the number function is true.
4052 *
4053 * Returns 0 or 1 depending on the results of the test.
4054 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004055static int
Owen Taylor3473f882001-02-23 17:55:21 +00004056xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
4057 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
4058 int i, ret = 0;
4059 xmlNodeSetPtr ns;
4060 xmlChar *str2;
4061
4062 if ((f == NULL) || (arg == NULL) ||
4063 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4064 xmlXPathFreeObject(arg);
4065 xmlXPathFreeObject(f);
4066 return(0);
4067 }
4068 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004069 if (ns != NULL) {
4070 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004071 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004072 if (str2 != NULL) {
4073 valuePush(ctxt,
4074 xmlXPathNewString(str2));
4075 xmlFree(str2);
4076 xmlXPathNumberFunction(ctxt, 1);
4077 valuePush(ctxt, xmlXPathObjectCopy(f));
4078 ret = xmlXPathCompareValues(ctxt, inf, strict);
4079 if (ret)
4080 break;
4081 }
4082 }
Owen Taylor3473f882001-02-23 17:55:21 +00004083 }
4084 xmlXPathFreeObject(arg);
4085 xmlXPathFreeObject(f);
4086 return(ret);
4087}
4088
4089/**
4090 * xmlXPathCompareNodeSetString:
4091 * @ctxt: the XPath Parser context
4092 * @inf: less than (1) or greater than (0)
4093 * @strict: is the comparison strict
4094 * @arg: the node set
4095 * @s: the value
4096 *
4097 * Implement the compare operation between a nodeset and a string
4098 * @ns < @val (1, 1, ...
4099 * @ns <= @val (1, 0, ...
4100 * @ns > @val (0, 1, ...
4101 * @ns >= @val (0, 0, ...
4102 *
4103 * If one object to be compared is a node-set and the other is a string,
4104 * then the comparison will be true if and only if there is a node in
4105 * the node-set such that the result of performing the comparison on the
4106 * string-value of the node and the other string is true.
4107 *
4108 * Returns 0 or 1 depending on the results of the test.
4109 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004110static int
Owen Taylor3473f882001-02-23 17:55:21 +00004111xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
4112 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
4113 int i, ret = 0;
4114 xmlNodeSetPtr ns;
4115 xmlChar *str2;
4116
4117 if ((s == NULL) || (arg == NULL) ||
4118 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4119 xmlXPathFreeObject(arg);
4120 xmlXPathFreeObject(s);
4121 return(0);
4122 }
4123 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004124 if (ns != NULL) {
4125 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004126 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004127 if (str2 != NULL) {
4128 valuePush(ctxt,
4129 xmlXPathNewString(str2));
4130 xmlFree(str2);
4131 valuePush(ctxt, xmlXPathObjectCopy(s));
4132 ret = xmlXPathCompareValues(ctxt, inf, strict);
4133 if (ret)
4134 break;
4135 }
4136 }
Owen Taylor3473f882001-02-23 17:55:21 +00004137 }
4138 xmlXPathFreeObject(arg);
4139 xmlXPathFreeObject(s);
4140 return(ret);
4141}
4142
4143/**
4144 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004145 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00004146 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004147 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00004148 * @arg2: the second node set object
4149 *
4150 * Implement the compare operation on nodesets:
4151 *
4152 * If both objects to be compared are node-sets, then the comparison
4153 * will be true if and only if there is a node in the first node-set
4154 * and a node in the second node-set such that the result of performing
4155 * the comparison on the string-values of the two nodes is true.
4156 * ....
4157 * When neither object to be compared is a node-set and the operator
4158 * is <=, <, >= or >, then the objects are compared by converting both
4159 * objects to numbers and comparing the numbers according to IEEE 754.
4160 * ....
4161 * The number function converts its argument to a number as follows:
4162 * - a string that consists of optional whitespace followed by an
4163 * optional minus sign followed by a Number followed by whitespace
4164 * is converted to the IEEE 754 number that is nearest (according
4165 * to the IEEE 754 round-to-nearest rule) to the mathematical value
4166 * represented by the string; any other string is converted to NaN
4167 *
4168 * Conclusion all nodes need to be converted first to their string value
4169 * and then the comparison must be done when possible
4170 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004171static int
4172xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00004173 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4174 int i, j, init = 0;
4175 double val1;
4176 double *values2;
4177 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004178 xmlNodeSetPtr ns1;
4179 xmlNodeSetPtr ns2;
4180
4181 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004182 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4183 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004184 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004185 }
Owen Taylor3473f882001-02-23 17:55:21 +00004186 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004187 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4188 xmlXPathFreeObject(arg1);
4189 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004190 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004191 }
Owen Taylor3473f882001-02-23 17:55:21 +00004192
4193 ns1 = arg1->nodesetval;
4194 ns2 = arg2->nodesetval;
4195
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004196 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004197 xmlXPathFreeObject(arg1);
4198 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004199 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004200 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004201 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004202 xmlXPathFreeObject(arg1);
4203 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004204 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004205 }
Owen Taylor3473f882001-02-23 17:55:21 +00004206
4207 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4208 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004209 xmlXPathFreeObject(arg1);
4210 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004211 return(0);
4212 }
4213 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004214 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004215 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004216 continue;
4217 for (j = 0;j < ns2->nodeNr;j++) {
4218 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004219 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004220 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004221 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004222 continue;
4223 if (inf && strict)
4224 ret = (val1 < values2[j]);
4225 else if (inf && !strict)
4226 ret = (val1 <= values2[j]);
4227 else if (!inf && strict)
4228 ret = (val1 > values2[j]);
4229 else if (!inf && !strict)
4230 ret = (val1 >= values2[j]);
4231 if (ret)
4232 break;
4233 }
4234 if (ret)
4235 break;
4236 init = 1;
4237 }
4238 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004239 xmlXPathFreeObject(arg1);
4240 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004241 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004242}
4243
4244/**
4245 * xmlXPathCompareNodeSetValue:
4246 * @ctxt: the XPath Parser context
4247 * @inf: less than (1) or greater than (0)
4248 * @strict: is the comparison strict
4249 * @arg: the node set
4250 * @val: the value
4251 *
4252 * Implement the compare operation between a nodeset and a value
4253 * @ns < @val (1, 1, ...
4254 * @ns <= @val (1, 0, ...
4255 * @ns > @val (0, 1, ...
4256 * @ns >= @val (0, 0, ...
4257 *
4258 * If one object to be compared is a node-set and the other is a boolean,
4259 * then the comparison will be true if and only if the result of performing
4260 * the comparison on the boolean and on the result of converting
4261 * the node-set to a boolean using the boolean function is true.
4262 *
4263 * Returns 0 or 1 depending on the results of the test.
4264 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004265static int
Owen Taylor3473f882001-02-23 17:55:21 +00004266xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4267 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4268 if ((val == NULL) || (arg == NULL) ||
4269 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4270 return(0);
4271
4272 switch(val->type) {
4273 case XPATH_NUMBER:
4274 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4275 case XPATH_NODESET:
4276 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004277 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004278 case XPATH_STRING:
4279 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4280 case XPATH_BOOLEAN:
4281 valuePush(ctxt, arg);
4282 xmlXPathBooleanFunction(ctxt, 1);
4283 valuePush(ctxt, val);
4284 return(xmlXPathCompareValues(ctxt, inf, strict));
4285 default:
4286 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004287 }
4288 return(0);
4289}
4290
4291/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004292 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00004293 * @arg: the nodeset object argument
4294 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00004295 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004296 *
4297 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4298 * If one object to be compared is a node-set and the other is a string,
4299 * then the comparison will be true if and only if there is a node in
4300 * the node-set such that the result of performing the comparison on the
4301 * string-value of the node and the other string is true.
4302 *
4303 * Returns 0 or 1 depending on the results of the test.
4304 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004305static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004306xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004307{
Owen Taylor3473f882001-02-23 17:55:21 +00004308 int i;
4309 xmlNodeSetPtr ns;
4310 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004311 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004312
4313 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004314 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4315 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004316 ns = arg->nodesetval;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004317 hash = xmlXPathStringHash(str);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004318 if (ns == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004319 return (0);
Daniel Veillard73c9c042001-07-05 20:02:54 +00004320 if (ns->nodeNr <= 0) {
4321 if (hash == 0)
William M. Brack0c022ad2002-07-12 00:56:01 +00004322 return(neq ^ 1);
4323 return(neq);
Daniel Veillard73c9c042001-07-05 20:02:54 +00004324 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004325 for (i = 0; i < ns->nodeNr; i++) {
4326 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4327 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4328 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4329 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004330 if (neq)
4331 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004332 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00004333 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
4334 if (neq)
4335 continue;
4336 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00004337 } else if (neq) {
4338 if (str2 != NULL)
4339 xmlFree(str2);
4340 return (1);
4341 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004342 if (str2 != NULL)
4343 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004344 } else if (neq)
4345 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00004346 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004347 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004348}
4349
4350/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004351 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00004352 * @arg: the nodeset object argument
4353 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00004354 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004355 *
4356 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4357 * If one object to be compared is a node-set and the other is a number,
4358 * then the comparison will be true if and only if there is a node in
4359 * the node-set such that the result of performing the comparison on the
4360 * number to be compared and on the result of converting the string-value
4361 * of that node to a number using the number function is true.
4362 *
4363 * Returns 0 or 1 depending on the results of the test.
4364 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004365static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004366xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
4367 xmlXPathObjectPtr arg, double f, int neq) {
4368 int i, ret=0;
4369 xmlNodeSetPtr ns;
4370 xmlChar *str2;
4371 xmlXPathObjectPtr val;
4372 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00004373
4374 if ((arg == NULL) ||
4375 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4376 return(0);
4377
William M. Brack0c022ad2002-07-12 00:56:01 +00004378 ns = arg->nodesetval;
4379 if (ns != NULL) {
4380 for (i=0;i<ns->nodeNr;i++) {
4381 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4382 if (str2 != NULL) {
4383 valuePush(ctxt, xmlXPathNewString(str2));
4384 xmlFree(str2);
4385 xmlXPathNumberFunction(ctxt, 1);
4386 val = valuePop(ctxt);
4387 v = val->floatval;
4388 xmlXPathFreeObject(val);
4389 if (!xmlXPathIsNaN(v)) {
4390 if ((!neq) && (v==f)) {
4391 ret = 1;
4392 break;
4393 } else if ((neq) && (v!=f)) {
4394 ret = 1;
4395 break;
4396 }
4397 }
4398 }
4399 }
4400 }
4401
4402 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004403}
4404
4405
4406/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004407 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00004408 * @arg1: first nodeset object argument
4409 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00004410 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004411 *
William M. Brack0c022ad2002-07-12 00:56:01 +00004412 * Implement the equal / not equal operation on XPath nodesets:
4413 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00004414 * If both objects to be compared are node-sets, then the comparison
4415 * will be true if and only if there is a node in the first node-set and
4416 * a node in the second node-set such that the result of performing the
4417 * comparison on the string-values of the two nodes is true.
4418 *
4419 * (needless to say, this is a costly operation)
4420 *
4421 * Returns 0 or 1 depending on the results of the test.
4422 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004423static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004424xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00004425 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004426 unsigned int *hashs1;
4427 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004428 xmlChar **values1;
4429 xmlChar **values2;
4430 int ret = 0;
4431 xmlNodeSetPtr ns1;
4432 xmlNodeSetPtr ns2;
4433
4434 if ((arg1 == NULL) ||
4435 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4436 return(0);
4437 if ((arg2 == NULL) ||
4438 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4439 return(0);
4440
4441 ns1 = arg1->nodesetval;
4442 ns2 = arg2->nodesetval;
4443
Daniel Veillard911f49a2001-04-07 15:39:35 +00004444 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004445 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004446 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004447 return(0);
4448
4449 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00004450 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00004451 */
William M. Brack0c022ad2002-07-12 00:56:01 +00004452 if (neq == 0)
4453 for (i = 0;i < ns1->nodeNr;i++)
4454 for (j = 0;j < ns2->nodeNr;j++)
4455 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4456 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00004457
4458 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
4459 if (values1 == NULL)
4460 return(0);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004461 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4462 if (hashs1 == NULL) {
4463 xmlFree(values1);
4464 return(0);
4465 }
Owen Taylor3473f882001-02-23 17:55:21 +00004466 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4467 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4468 if (values2 == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004469 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004470 xmlFree(values1);
4471 return(0);
4472 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004473 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4474 if (hashs2 == NULL) {
4475 xmlFree(hashs1);
4476 xmlFree(values1);
4477 xmlFree(values2);
4478 return(0);
4479 }
Owen Taylor3473f882001-02-23 17:55:21 +00004480 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4481 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004482 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004483 for (j = 0;j < ns2->nodeNr;j++) {
4484 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004485 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004486 if (hashs1[i] != hashs2[j]) {
4487 if (neq) {
4488 ret = 1;
4489 break;
4490 }
4491 }
4492 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004493 if (values1[i] == NULL)
4494 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4495 if (values2[j] == NULL)
4496 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004497 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004498 if (ret)
4499 break;
4500 }
Owen Taylor3473f882001-02-23 17:55:21 +00004501 }
4502 if (ret)
4503 break;
4504 }
4505 for (i = 0;i < ns1->nodeNr;i++)
4506 if (values1[i] != NULL)
4507 xmlFree(values1[i]);
4508 for (j = 0;j < ns2->nodeNr;j++)
4509 if (values2[j] != NULL)
4510 xmlFree(values2[j]);
4511 xmlFree(values1);
4512 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004513 xmlFree(hashs1);
4514 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004515 return(ret);
4516}
4517
William M. Brack0c022ad2002-07-12 00:56:01 +00004518static int
4519xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
4520 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00004521 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00004522 /*
4523 *At this point we are assured neither arg1 nor arg2
4524 *is a nodeset, so we can just pick the appropriate routine.
4525 */
Owen Taylor3473f882001-02-23 17:55:21 +00004526 switch (arg1->type) {
4527 case XPATH_UNDEFINED:
4528#ifdef DEBUG_EXPR
4529 xmlGenericError(xmlGenericErrorContext,
4530 "Equal: undefined\n");
4531#endif
4532 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004533 case XPATH_BOOLEAN:
4534 switch (arg2->type) {
4535 case XPATH_UNDEFINED:
4536#ifdef DEBUG_EXPR
4537 xmlGenericError(xmlGenericErrorContext,
4538 "Equal: undefined\n");
4539#endif
4540 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004541 case XPATH_BOOLEAN:
4542#ifdef DEBUG_EXPR
4543 xmlGenericError(xmlGenericErrorContext,
4544 "Equal: %d boolean %d \n",
4545 arg1->boolval, arg2->boolval);
4546#endif
4547 ret = (arg1->boolval == arg2->boolval);
4548 break;
4549 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00004550 ret = (arg1->boolval ==
4551 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004552 break;
4553 case XPATH_STRING:
4554 if ((arg2->stringval == NULL) ||
4555 (arg2->stringval[0] == 0)) ret = 0;
4556 else
4557 ret = 1;
4558 ret = (arg1->boolval == ret);
4559 break;
4560 case XPATH_USERS:
4561 case XPATH_POINT:
4562 case XPATH_RANGE:
4563 case XPATH_LOCATIONSET:
4564 TODO
4565 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004566 case XPATH_NODESET:
4567 case XPATH_XSLT_TREE:
4568 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004569 }
4570 break;
4571 case XPATH_NUMBER:
4572 switch (arg2->type) {
4573 case XPATH_UNDEFINED:
4574#ifdef DEBUG_EXPR
4575 xmlGenericError(xmlGenericErrorContext,
4576 "Equal: undefined\n");
4577#endif
4578 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004579 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00004580 ret = (arg2->boolval==
4581 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004582 break;
4583 case XPATH_STRING:
4584 valuePush(ctxt, arg2);
4585 xmlXPathNumberFunction(ctxt, 1);
4586 arg2 = valuePop(ctxt);
4587 /* no break on purpose */
4588 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004589 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004590 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4591 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004592 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4593 if (xmlXPathIsInf(arg2->floatval) == 1)
4594 ret = 1;
4595 else
4596 ret = 0;
4597 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4598 if (xmlXPathIsInf(arg2->floatval) == -1)
4599 ret = 1;
4600 else
4601 ret = 0;
4602 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4603 if (xmlXPathIsInf(arg1->floatval) == 1)
4604 ret = 1;
4605 else
4606 ret = 0;
4607 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4608 if (xmlXPathIsInf(arg1->floatval) == -1)
4609 ret = 1;
4610 else
4611 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004612 } else {
4613 ret = (arg1->floatval == arg2->floatval);
4614 }
Owen Taylor3473f882001-02-23 17:55:21 +00004615 break;
4616 case XPATH_USERS:
4617 case XPATH_POINT:
4618 case XPATH_RANGE:
4619 case XPATH_LOCATIONSET:
4620 TODO
4621 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004622 case XPATH_NODESET:
4623 case XPATH_XSLT_TREE:
4624 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004625 }
4626 break;
4627 case XPATH_STRING:
4628 switch (arg2->type) {
4629 case XPATH_UNDEFINED:
4630#ifdef DEBUG_EXPR
4631 xmlGenericError(xmlGenericErrorContext,
4632 "Equal: undefined\n");
4633#endif
4634 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004635 case XPATH_BOOLEAN:
4636 if ((arg1->stringval == NULL) ||
4637 (arg1->stringval[0] == 0)) ret = 0;
4638 else
4639 ret = 1;
4640 ret = (arg2->boolval == ret);
4641 break;
4642 case XPATH_STRING:
4643 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4644 break;
4645 case XPATH_NUMBER:
4646 valuePush(ctxt, arg1);
4647 xmlXPathNumberFunction(ctxt, 1);
4648 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004649 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004650 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4651 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004652 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4653 if (xmlXPathIsInf(arg2->floatval) == 1)
4654 ret = 1;
4655 else
4656 ret = 0;
4657 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4658 if (xmlXPathIsInf(arg2->floatval) == -1)
4659 ret = 1;
4660 else
4661 ret = 0;
4662 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4663 if (xmlXPathIsInf(arg1->floatval) == 1)
4664 ret = 1;
4665 else
4666 ret = 0;
4667 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4668 if (xmlXPathIsInf(arg1->floatval) == -1)
4669 ret = 1;
4670 else
4671 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004672 } else {
4673 ret = (arg1->floatval == arg2->floatval);
4674 }
Owen Taylor3473f882001-02-23 17:55:21 +00004675 break;
4676 case XPATH_USERS:
4677 case XPATH_POINT:
4678 case XPATH_RANGE:
4679 case XPATH_LOCATIONSET:
4680 TODO
4681 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004682 case XPATH_NODESET:
4683 case XPATH_XSLT_TREE:
4684 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004685 }
4686 break;
4687 case XPATH_USERS:
4688 case XPATH_POINT:
4689 case XPATH_RANGE:
4690 case XPATH_LOCATIONSET:
4691 TODO
4692 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004693 case XPATH_NODESET:
4694 case XPATH_XSLT_TREE:
4695 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004696 }
4697 xmlXPathFreeObject(arg1);
4698 xmlXPathFreeObject(arg2);
4699 return(ret);
4700}
4701
William M. Brack0c022ad2002-07-12 00:56:01 +00004702/**
4703 * xmlXPathEqualValues:
4704 * @ctxt: the XPath Parser context
4705 *
4706 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4707 *
4708 * Returns 0 or 1 depending on the results of the test.
4709 */
4710int
4711xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4712 xmlXPathObjectPtr arg1, arg2, argtmp;
4713 int ret = 0;
4714
4715 arg2 = valuePop(ctxt);
4716 arg1 = valuePop(ctxt);
4717 if ((arg1 == NULL) || (arg2 == NULL)) {
4718 if (arg1 != NULL)
4719 xmlXPathFreeObject(arg1);
4720 else
4721 xmlXPathFreeObject(arg2);
4722 XP_ERROR0(XPATH_INVALID_OPERAND);
4723 }
4724
4725 if (arg1 == arg2) {
4726#ifdef DEBUG_EXPR
4727 xmlGenericError(xmlGenericErrorContext,
4728 "Equal: by pointer\n");
4729#endif
4730 return(1);
4731 }
4732
4733 /*
4734 *If either argument is a nodeset, it's a 'special case'
4735 */
4736 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4737 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4738 /*
4739 *Hack it to assure arg1 is the nodeset
4740 */
4741 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4742 argtmp = arg2;
4743 arg2 = arg1;
4744 arg1 = argtmp;
4745 }
4746 switch (arg2->type) {
4747 case XPATH_UNDEFINED:
4748#ifdef DEBUG_EXPR
4749 xmlGenericError(xmlGenericErrorContext,
4750 "Equal: undefined\n");
4751#endif
4752 break;
4753 case XPATH_NODESET:
4754 case XPATH_XSLT_TREE:
4755 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
4756 break;
4757 case XPATH_BOOLEAN:
4758 if ((arg1->nodesetval == NULL) ||
4759 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4760 else
4761 ret = 1;
4762 ret = (ret == arg2->boolval);
4763 break;
4764 case XPATH_NUMBER:
4765 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
4766 break;
4767 case XPATH_STRING:
4768 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
4769 break;
4770 case XPATH_USERS:
4771 case XPATH_POINT:
4772 case XPATH_RANGE:
4773 case XPATH_LOCATIONSET:
4774 TODO
4775 break;
4776 }
4777 xmlXPathFreeObject(arg1);
4778 xmlXPathFreeObject(arg2);
4779 return(ret);
4780 }
4781
4782 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4783}
4784
4785/**
4786 * xmlXPathNotEqualValues:
4787 * @ctxt: the XPath Parser context
4788 *
4789 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4790 *
4791 * Returns 0 or 1 depending on the results of the test.
4792 */
4793int
4794xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
4795 xmlXPathObjectPtr arg1, arg2, argtmp;
4796 int ret = 0;
4797
4798 arg2 = valuePop(ctxt);
4799 arg1 = valuePop(ctxt);
4800 if ((arg1 == NULL) || (arg2 == NULL)) {
4801 if (arg1 != NULL)
4802 xmlXPathFreeObject(arg1);
4803 else
4804 xmlXPathFreeObject(arg2);
4805 XP_ERROR0(XPATH_INVALID_OPERAND);
4806 }
4807
4808 if (arg1 == arg2) {
4809#ifdef DEBUG_EXPR
4810 xmlGenericError(xmlGenericErrorContext,
4811 "NotEqual: by pointer\n");
4812#endif
4813 return(0);
4814 }
4815
4816 /*
4817 *If either argument is a nodeset, it's a 'special case'
4818 */
4819 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4820 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4821 /*
4822 *Hack it to assure arg1 is the nodeset
4823 */
4824 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4825 argtmp = arg2;
4826 arg2 = arg1;
4827 arg1 = argtmp;
4828 }
4829 switch (arg2->type) {
4830 case XPATH_UNDEFINED:
4831#ifdef DEBUG_EXPR
4832 xmlGenericError(xmlGenericErrorContext,
4833 "NotEqual: undefined\n");
4834#endif
4835 break;
4836 case XPATH_NODESET:
4837 case XPATH_XSLT_TREE:
4838 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
4839 break;
4840 case XPATH_BOOLEAN:
4841 if ((arg1->nodesetval == NULL) ||
4842 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4843 else
4844 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00004845 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00004846 break;
4847 case XPATH_NUMBER:
4848 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
4849 break;
4850 case XPATH_STRING:
4851 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
4852 break;
4853 case XPATH_USERS:
4854 case XPATH_POINT:
4855 case XPATH_RANGE:
4856 case XPATH_LOCATIONSET:
4857 TODO
4858 break;
4859 }
4860 xmlXPathFreeObject(arg1);
4861 xmlXPathFreeObject(arg2);
4862 return(ret);
4863 }
4864
4865 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4866}
Owen Taylor3473f882001-02-23 17:55:21 +00004867
4868/**
4869 * xmlXPathCompareValues:
4870 * @ctxt: the XPath Parser context
4871 * @inf: less than (1) or greater than (0)
4872 * @strict: is the comparison strict
4873 *
4874 * Implement the compare operation on XPath objects:
4875 * @arg1 < @arg2 (1, 1, ...
4876 * @arg1 <= @arg2 (1, 0, ...
4877 * @arg1 > @arg2 (0, 1, ...
4878 * @arg1 >= @arg2 (0, 0, ...
4879 *
4880 * When neither object to be compared is a node-set and the operator is
4881 * <=, <, >=, >, then the objects are compared by converted both objects
4882 * to numbers and comparing the numbers according to IEEE 754. The <
4883 * comparison will be true if and only if the first number is less than the
4884 * second number. The <= comparison will be true if and only if the first
4885 * number is less than or equal to the second number. The > comparison
4886 * will be true if and only if the first number is greater than the second
4887 * number. The >= comparison will be true if and only if the first number
4888 * is greater than or equal to the second number.
4889 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004890 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00004891 */
4892int
4893xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004894 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004895 xmlXPathObjectPtr arg1, arg2;
4896
William M. Brack0c022ad2002-07-12 00:56:01 +00004897 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00004898 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00004899 if ((arg1 == NULL) || (arg2 == NULL)) {
4900 if (arg1 != NULL)
4901 xmlXPathFreeObject(arg1);
4902 else
4903 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004904 XP_ERROR0(XPATH_INVALID_OPERAND);
4905 }
4906
William M. Brack0c022ad2002-07-12 00:56:01 +00004907 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4908 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4909 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
4910 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004911 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004912 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00004913 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004914 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
4915 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004916 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004917 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
4918 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00004919 }
4920 }
4921 return(ret);
4922 }
4923
4924 if (arg1->type != XPATH_NUMBER) {
4925 valuePush(ctxt, arg1);
4926 xmlXPathNumberFunction(ctxt, 1);
4927 arg1 = valuePop(ctxt);
4928 }
4929 if (arg1->type != XPATH_NUMBER) {
4930 xmlXPathFreeObject(arg1);
4931 xmlXPathFreeObject(arg2);
4932 XP_ERROR0(XPATH_INVALID_OPERAND);
4933 }
4934 if (arg2->type != XPATH_NUMBER) {
4935 valuePush(ctxt, arg2);
4936 xmlXPathNumberFunction(ctxt, 1);
4937 arg2 = valuePop(ctxt);
4938 }
4939 if (arg2->type != XPATH_NUMBER) {
4940 xmlXPathFreeObject(arg1);
4941 xmlXPathFreeObject(arg2);
4942 XP_ERROR0(XPATH_INVALID_OPERAND);
4943 }
4944 /*
4945 * Add tests for infinity and nan
4946 * => feedback on 3.4 for Inf and NaN
4947 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004948 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00004949 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004950 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004951 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004952 arg1i=xmlXPathIsInf(arg1->floatval);
4953 arg2i=xmlXPathIsInf(arg2->floatval);
4954 if (inf && strict) {
4955 if ((arg1i == -1 && arg2i != -1) ||
4956 (arg2i == 1 && arg1i != 1)) {
4957 ret = 1;
4958 } else if (arg1i == 0 && arg2i == 0) {
4959 ret = (arg1->floatval < arg2->floatval);
4960 } else {
4961 ret = 0;
4962 }
4963 }
4964 else if (inf && !strict) {
4965 if (arg1i == -1 || arg2i == 1) {
4966 ret = 1;
4967 } else if (arg1i == 0 && arg2i == 0) {
4968 ret = (arg1->floatval <= arg2->floatval);
4969 } else {
4970 ret = 0;
4971 }
4972 }
4973 else if (!inf && strict) {
4974 if ((arg1i == 1 && arg2i != 1) ||
4975 (arg2i == -1 && arg1i != -1)) {
4976 ret = 1;
4977 } else if (arg1i == 0 && arg2i == 0) {
4978 ret = (arg1->floatval > arg2->floatval);
4979 } else {
4980 ret = 0;
4981 }
4982 }
4983 else if (!inf && !strict) {
4984 if (arg1i == 1 || arg2i == -1) {
4985 ret = 1;
4986 } else if (arg1i == 0 && arg2i == 0) {
4987 ret = (arg1->floatval >= arg2->floatval);
4988 } else {
4989 ret = 0;
4990 }
4991 }
Daniel Veillard21458c82002-03-27 16:12:22 +00004992 }
Owen Taylor3473f882001-02-23 17:55:21 +00004993 xmlXPathFreeObject(arg1);
4994 xmlXPathFreeObject(arg2);
4995 return(ret);
4996}
4997
4998/**
4999 * xmlXPathValueFlipSign:
5000 * @ctxt: the XPath Parser context
5001 *
5002 * Implement the unary - operation on an XPath object
5003 * The numeric operators convert their operands to numbers as if
5004 * by calling the number function.
5005 */
5006void
5007xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005008 CAST_TO_NUMBER;
5009 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005010 if (xmlXPathIsNaN(ctxt->value->floatval))
5011 ctxt->value->floatval=xmlXPathNAN;
5012 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
5013 ctxt->value->floatval=xmlXPathNINF;
5014 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
5015 ctxt->value->floatval=xmlXPathPINF;
5016 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005017 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
5018 ctxt->value->floatval = xmlXPathNZERO;
5019 else
5020 ctxt->value->floatval = 0;
5021 }
5022 else
5023 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00005024}
5025
5026/**
5027 * xmlXPathAddValues:
5028 * @ctxt: the XPath Parser context
5029 *
5030 * Implement the add operation on XPath objects:
5031 * The numeric operators convert their operands to numbers as if
5032 * by calling the number function.
5033 */
5034void
5035xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
5036 xmlXPathObjectPtr arg;
5037 double val;
5038
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005039 arg = valuePop(ctxt);
5040 if (arg == NULL)
5041 XP_ERROR(XPATH_INVALID_OPERAND);
5042 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005043 xmlXPathFreeObject(arg);
5044
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005045 CAST_TO_NUMBER;
5046 CHECK_TYPE(XPATH_NUMBER);
5047 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00005048}
5049
5050/**
5051 * xmlXPathSubValues:
5052 * @ctxt: the XPath Parser context
5053 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005054 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00005055 * The numeric operators convert their operands to numbers as if
5056 * by calling the number function.
5057 */
5058void
5059xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
5060 xmlXPathObjectPtr arg;
5061 double val;
5062
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005063 arg = valuePop(ctxt);
5064 if (arg == NULL)
5065 XP_ERROR(XPATH_INVALID_OPERAND);
5066 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005067 xmlXPathFreeObject(arg);
5068
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005069 CAST_TO_NUMBER;
5070 CHECK_TYPE(XPATH_NUMBER);
5071 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005072}
5073
5074/**
5075 * xmlXPathMultValues:
5076 * @ctxt: the XPath Parser context
5077 *
5078 * Implement the multiply operation on XPath objects:
5079 * The numeric operators convert their operands to numbers as if
5080 * by calling the number function.
5081 */
5082void
5083xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
5084 xmlXPathObjectPtr arg;
5085 double val;
5086
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005087 arg = valuePop(ctxt);
5088 if (arg == NULL)
5089 XP_ERROR(XPATH_INVALID_OPERAND);
5090 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005091 xmlXPathFreeObject(arg);
5092
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005093 CAST_TO_NUMBER;
5094 CHECK_TYPE(XPATH_NUMBER);
5095 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005096}
5097
5098/**
5099 * xmlXPathDivValues:
5100 * @ctxt: the XPath Parser context
5101 *
5102 * Implement the div operation on XPath objects @arg1 / @arg2:
5103 * The numeric operators convert their operands to numbers as if
5104 * by calling the number function.
5105 */
5106void
5107xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
5108 xmlXPathObjectPtr arg;
5109 double val;
5110
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005111 arg = valuePop(ctxt);
5112 if (arg == NULL)
5113 XP_ERROR(XPATH_INVALID_OPERAND);
5114 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005115 xmlXPathFreeObject(arg);
5116
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005117 CAST_TO_NUMBER;
5118 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005119 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
5120 ctxt->value->floatval = xmlXPathNAN;
5121 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005122 if (ctxt->value->floatval == 0)
5123 ctxt->value->floatval = xmlXPathNAN;
5124 else if (ctxt->value->floatval > 0)
5125 ctxt->value->floatval = xmlXPathNINF;
5126 else if (ctxt->value->floatval < 0)
5127 ctxt->value->floatval = xmlXPathPINF;
5128 }
5129 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00005130 if (ctxt->value->floatval == 0)
5131 ctxt->value->floatval = xmlXPathNAN;
5132 else if (ctxt->value->floatval > 0)
5133 ctxt->value->floatval = xmlXPathPINF;
5134 else if (ctxt->value->floatval < 0)
5135 ctxt->value->floatval = xmlXPathNINF;
5136 } else
5137 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005138}
5139
5140/**
5141 * xmlXPathModValues:
5142 * @ctxt: the XPath Parser context
5143 *
5144 * Implement the mod operation on XPath objects: @arg1 / @arg2
5145 * The numeric operators convert their operands to numbers as if
5146 * by calling the number function.
5147 */
5148void
5149xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
5150 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005151 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00005152
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005153 arg = valuePop(ctxt);
5154 if (arg == NULL)
5155 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005156 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005157 xmlXPathFreeObject(arg);
5158
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005159 CAST_TO_NUMBER;
5160 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005161 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00005162 if (arg2 == 0)
5163 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005164 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00005165 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005166 }
Owen Taylor3473f882001-02-23 17:55:21 +00005167}
5168
5169/************************************************************************
5170 * *
5171 * The traversal functions *
5172 * *
5173 ************************************************************************/
5174
Owen Taylor3473f882001-02-23 17:55:21 +00005175/*
5176 * A traversal function enumerates nodes along an axis.
5177 * Initially it must be called with NULL, and it indicates
5178 * termination on the axis by returning NULL.
5179 */
5180typedef xmlNodePtr (*xmlXPathTraversalFunction)
5181 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
5182
5183/**
5184 * xmlXPathNextSelf:
5185 * @ctxt: the XPath Parser context
5186 * @cur: the current node in the traversal
5187 *
5188 * Traversal function for the "self" direction
5189 * The self axis contains just the context node itself
5190 *
5191 * Returns the next element following that axis
5192 */
5193xmlNodePtr
5194xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5195 if (cur == NULL)
5196 return(ctxt->context->node);
5197 return(NULL);
5198}
5199
5200/**
5201 * xmlXPathNextChild:
5202 * @ctxt: the XPath Parser context
5203 * @cur: the current node in the traversal
5204 *
5205 * Traversal function for the "child" direction
5206 * The child axis contains the children of the context node in document order.
5207 *
5208 * Returns the next element following that axis
5209 */
5210xmlNodePtr
5211xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5212 if (cur == NULL) {
5213 if (ctxt->context->node == NULL) return(NULL);
5214 switch (ctxt->context->node->type) {
5215 case XML_ELEMENT_NODE:
5216 case XML_TEXT_NODE:
5217 case XML_CDATA_SECTION_NODE:
5218 case XML_ENTITY_REF_NODE:
5219 case XML_ENTITY_NODE:
5220 case XML_PI_NODE:
5221 case XML_COMMENT_NODE:
5222 case XML_NOTATION_NODE:
5223 case XML_DTD_NODE:
5224 return(ctxt->context->node->children);
5225 case XML_DOCUMENT_NODE:
5226 case XML_DOCUMENT_TYPE_NODE:
5227 case XML_DOCUMENT_FRAG_NODE:
5228 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005229#ifdef LIBXML_DOCB_ENABLED
5230 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005231#endif
5232 return(((xmlDocPtr) ctxt->context->node)->children);
5233 case XML_ELEMENT_DECL:
5234 case XML_ATTRIBUTE_DECL:
5235 case XML_ENTITY_DECL:
5236 case XML_ATTRIBUTE_NODE:
5237 case XML_NAMESPACE_DECL:
5238 case XML_XINCLUDE_START:
5239 case XML_XINCLUDE_END:
5240 return(NULL);
5241 }
5242 return(NULL);
5243 }
5244 if ((cur->type == XML_DOCUMENT_NODE) ||
5245 (cur->type == XML_HTML_DOCUMENT_NODE))
5246 return(NULL);
5247 return(cur->next);
5248}
5249
5250/**
5251 * xmlXPathNextDescendant:
5252 * @ctxt: the XPath Parser context
5253 * @cur: the current node in the traversal
5254 *
5255 * Traversal function for the "descendant" direction
5256 * the descendant axis contains the descendants of the context node in document
5257 * order; a descendant is a child or a child of a child and so on.
5258 *
5259 * Returns the next element following that axis
5260 */
5261xmlNodePtr
5262xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5263 if (cur == NULL) {
5264 if (ctxt->context->node == NULL)
5265 return(NULL);
5266 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5267 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5268 return(NULL);
5269
5270 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5271 return(ctxt->context->doc->children);
5272 return(ctxt->context->node->children);
5273 }
5274
Daniel Veillard567e1b42001-08-01 15:53:47 +00005275 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00005276 /*
5277 * Do not descend on entities declarations
5278 */
5279 if (cur->children->type != XML_ENTITY_DECL) {
5280 cur = cur->children;
5281 /*
5282 * Skip DTDs
5283 */
5284 if (cur->type != XML_DTD_NODE)
5285 return(cur);
5286 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00005287 }
5288
5289 if (cur == ctxt->context->node) return(NULL);
5290
Daniel Veillard68e9e742002-11-16 15:35:11 +00005291 while (cur->next != NULL) {
5292 cur = cur->next;
5293 if ((cur->type != XML_ENTITY_DECL) &&
5294 (cur->type != XML_DTD_NODE))
5295 return(cur);
5296 }
Owen Taylor3473f882001-02-23 17:55:21 +00005297
5298 do {
5299 cur = cur->parent;
5300 if (cur == NULL) return(NULL);
5301 if (cur == ctxt->context->node) return(NULL);
5302 if (cur->next != NULL) {
5303 cur = cur->next;
5304 return(cur);
5305 }
5306 } while (cur != NULL);
5307 return(cur);
5308}
5309
5310/**
5311 * xmlXPathNextDescendantOrSelf:
5312 * @ctxt: the XPath Parser context
5313 * @cur: the current node in the traversal
5314 *
5315 * Traversal function for the "descendant-or-self" direction
5316 * the descendant-or-self axis contains the context node and the descendants
5317 * of the context node in document order; thus the context node is the first
5318 * node on the axis, and the first child of the context node is the second node
5319 * on the axis
5320 *
5321 * Returns the next element following that axis
5322 */
5323xmlNodePtr
5324xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5325 if (cur == NULL) {
5326 if (ctxt->context->node == NULL)
5327 return(NULL);
5328 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5329 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5330 return(NULL);
5331 return(ctxt->context->node);
5332 }
5333
5334 return(xmlXPathNextDescendant(ctxt, cur));
5335}
5336
5337/**
5338 * xmlXPathNextParent:
5339 * @ctxt: the XPath Parser context
5340 * @cur: the current node in the traversal
5341 *
5342 * Traversal function for the "parent" direction
5343 * The parent axis contains the parent of the context node, if there is one.
5344 *
5345 * Returns the next element following that axis
5346 */
5347xmlNodePtr
5348xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5349 /*
5350 * the parent of an attribute or namespace node is the element
5351 * to which the attribute or namespace node is attached
5352 * Namespace handling !!!
5353 */
5354 if (cur == NULL) {
5355 if (ctxt->context->node == NULL) return(NULL);
5356 switch (ctxt->context->node->type) {
5357 case XML_ELEMENT_NODE:
5358 case XML_TEXT_NODE:
5359 case XML_CDATA_SECTION_NODE:
5360 case XML_ENTITY_REF_NODE:
5361 case XML_ENTITY_NODE:
5362 case XML_PI_NODE:
5363 case XML_COMMENT_NODE:
5364 case XML_NOTATION_NODE:
5365 case XML_DTD_NODE:
5366 case XML_ELEMENT_DECL:
5367 case XML_ATTRIBUTE_DECL:
5368 case XML_XINCLUDE_START:
5369 case XML_XINCLUDE_END:
5370 case XML_ENTITY_DECL:
5371 if (ctxt->context->node->parent == NULL)
5372 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005373 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005374 ((ctxt->context->node->parent->name[0] == ' ') ||
5375 (xmlStrEqual(ctxt->context->node->parent->name,
5376 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005377 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005378 return(ctxt->context->node->parent);
5379 case XML_ATTRIBUTE_NODE: {
5380 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5381
5382 return(att->parent);
5383 }
5384 case XML_DOCUMENT_NODE:
5385 case XML_DOCUMENT_TYPE_NODE:
5386 case XML_DOCUMENT_FRAG_NODE:
5387 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005388#ifdef LIBXML_DOCB_ENABLED
5389 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005390#endif
5391 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005392 case XML_NAMESPACE_DECL: {
5393 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5394
5395 if ((ns->next != NULL) &&
5396 (ns->next->type != XML_NAMESPACE_DECL))
5397 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005398 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005399 }
Owen Taylor3473f882001-02-23 17:55:21 +00005400 }
5401 }
5402 return(NULL);
5403}
5404
5405/**
5406 * xmlXPathNextAncestor:
5407 * @ctxt: the XPath Parser context
5408 * @cur: the current node in the traversal
5409 *
5410 * Traversal function for the "ancestor" direction
5411 * the ancestor axis contains the ancestors of the context node; the ancestors
5412 * of the context node consist of the parent of context node and the parent's
5413 * parent and so on; the nodes are ordered in reverse document order; thus the
5414 * parent is the first node on the axis, and the parent's parent is the second
5415 * node on the axis
5416 *
5417 * Returns the next element following that axis
5418 */
5419xmlNodePtr
5420xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5421 /*
5422 * the parent of an attribute or namespace node is the element
5423 * to which the attribute or namespace node is attached
5424 * !!!!!!!!!!!!!
5425 */
5426 if (cur == NULL) {
5427 if (ctxt->context->node == NULL) return(NULL);
5428 switch (ctxt->context->node->type) {
5429 case XML_ELEMENT_NODE:
5430 case XML_TEXT_NODE:
5431 case XML_CDATA_SECTION_NODE:
5432 case XML_ENTITY_REF_NODE:
5433 case XML_ENTITY_NODE:
5434 case XML_PI_NODE:
5435 case XML_COMMENT_NODE:
5436 case XML_DTD_NODE:
5437 case XML_ELEMENT_DECL:
5438 case XML_ATTRIBUTE_DECL:
5439 case XML_ENTITY_DECL:
5440 case XML_NOTATION_NODE:
5441 case XML_XINCLUDE_START:
5442 case XML_XINCLUDE_END:
5443 if (ctxt->context->node->parent == NULL)
5444 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005445 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005446 ((ctxt->context->node->parent->name[0] == ' ') ||
5447 (xmlStrEqual(ctxt->context->node->parent->name,
5448 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005449 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005450 return(ctxt->context->node->parent);
5451 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005452 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005453
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005454 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005455 }
5456 case XML_DOCUMENT_NODE:
5457 case XML_DOCUMENT_TYPE_NODE:
5458 case XML_DOCUMENT_FRAG_NODE:
5459 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005460#ifdef LIBXML_DOCB_ENABLED
5461 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005462#endif
5463 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005464 case XML_NAMESPACE_DECL: {
5465 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5466
5467 if ((ns->next != NULL) &&
5468 (ns->next->type != XML_NAMESPACE_DECL))
5469 return((xmlNodePtr) ns->next);
5470 /* Bad, how did that namespace ended-up there ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005471 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005472 }
Owen Taylor3473f882001-02-23 17:55:21 +00005473 }
5474 return(NULL);
5475 }
5476 if (cur == ctxt->context->doc->children)
5477 return((xmlNodePtr) ctxt->context->doc);
5478 if (cur == (xmlNodePtr) ctxt->context->doc)
5479 return(NULL);
5480 switch (cur->type) {
5481 case XML_ELEMENT_NODE:
5482 case XML_TEXT_NODE:
5483 case XML_CDATA_SECTION_NODE:
5484 case XML_ENTITY_REF_NODE:
5485 case XML_ENTITY_NODE:
5486 case XML_PI_NODE:
5487 case XML_COMMENT_NODE:
5488 case XML_NOTATION_NODE:
5489 case XML_DTD_NODE:
5490 case XML_ELEMENT_DECL:
5491 case XML_ATTRIBUTE_DECL:
5492 case XML_ENTITY_DECL:
5493 case XML_XINCLUDE_START:
5494 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005495 if (cur->parent == NULL)
5496 return(NULL);
5497 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005498 ((cur->parent->name[0] == ' ') ||
5499 (xmlStrEqual(cur->parent->name,
5500 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005501 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005502 return(cur->parent);
5503 case XML_ATTRIBUTE_NODE: {
5504 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5505
5506 return(att->parent);
5507 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005508 case XML_NAMESPACE_DECL: {
5509 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5510
5511 if ((ns->next != NULL) &&
5512 (ns->next->type != XML_NAMESPACE_DECL))
5513 return((xmlNodePtr) ns->next);
5514 /* Bad, how did that namespace ended-up there ? */
5515 return(NULL);
5516 }
Owen Taylor3473f882001-02-23 17:55:21 +00005517 case XML_DOCUMENT_NODE:
5518 case XML_DOCUMENT_TYPE_NODE:
5519 case XML_DOCUMENT_FRAG_NODE:
5520 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005521#ifdef LIBXML_DOCB_ENABLED
5522 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005523#endif
5524 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005525 }
5526 return(NULL);
5527}
5528
5529/**
5530 * xmlXPathNextAncestorOrSelf:
5531 * @ctxt: the XPath Parser context
5532 * @cur: the current node in the traversal
5533 *
5534 * Traversal function for the "ancestor-or-self" direction
5535 * he ancestor-or-self axis contains the context node and ancestors of
5536 * the context node in reverse document order; thus the context node is
5537 * the first node on the axis, and the context node's parent the second;
5538 * parent here is defined the same as with the parent axis.
5539 *
5540 * Returns the next element following that axis
5541 */
5542xmlNodePtr
5543xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5544 if (cur == NULL)
5545 return(ctxt->context->node);
5546 return(xmlXPathNextAncestor(ctxt, cur));
5547}
5548
5549/**
5550 * xmlXPathNextFollowingSibling:
5551 * @ctxt: the XPath Parser context
5552 * @cur: the current node in the traversal
5553 *
5554 * Traversal function for the "following-sibling" direction
5555 * The following-sibling axis contains the following siblings of the context
5556 * node in document order.
5557 *
5558 * Returns the next element following that axis
5559 */
5560xmlNodePtr
5561xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5562 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5563 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5564 return(NULL);
5565 if (cur == (xmlNodePtr) ctxt->context->doc)
5566 return(NULL);
5567 if (cur == NULL)
5568 return(ctxt->context->node->next);
5569 return(cur->next);
5570}
5571
5572/**
5573 * xmlXPathNextPrecedingSibling:
5574 * @ctxt: the XPath Parser context
5575 * @cur: the current node in the traversal
5576 *
5577 * Traversal function for the "preceding-sibling" direction
5578 * The preceding-sibling axis contains the preceding siblings of the context
5579 * node in reverse document order; the first preceding sibling is first on the
5580 * axis; the sibling preceding that node is the second on the axis and so on.
5581 *
5582 * Returns the next element following that axis
5583 */
5584xmlNodePtr
5585xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5586 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5587 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5588 return(NULL);
5589 if (cur == (xmlNodePtr) ctxt->context->doc)
5590 return(NULL);
5591 if (cur == NULL)
5592 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005593 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5594 cur = cur->prev;
5595 if (cur == NULL)
5596 return(ctxt->context->node->prev);
5597 }
Owen Taylor3473f882001-02-23 17:55:21 +00005598 return(cur->prev);
5599}
5600
5601/**
5602 * xmlXPathNextFollowing:
5603 * @ctxt: the XPath Parser context
5604 * @cur: the current node in the traversal
5605 *
5606 * Traversal function for the "following" direction
5607 * The following axis contains all nodes in the same document as the context
5608 * node that are after the context node in document order, excluding any
5609 * descendants and excluding attribute nodes and namespace nodes; the nodes
5610 * are ordered in document order
5611 *
5612 * Returns the next element following that axis
5613 */
5614xmlNodePtr
5615xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5616 if (cur != NULL && cur->children != NULL)
5617 return cur->children ;
5618 if (cur == NULL) cur = ctxt->context->node;
5619 if (cur == NULL) return(NULL) ; /* ERROR */
5620 if (cur->next != NULL) return(cur->next) ;
5621 do {
5622 cur = cur->parent;
5623 if (cur == NULL) return(NULL);
5624 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5625 if (cur->next != NULL) return(cur->next);
5626 } while (cur != NULL);
5627 return(cur);
5628}
5629
5630/*
5631 * xmlXPathIsAncestor:
5632 * @ancestor: the ancestor node
5633 * @node: the current node
5634 *
5635 * Check that @ancestor is a @node's ancestor
5636 *
5637 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5638 */
5639static int
5640xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5641 if ((ancestor == NULL) || (node == NULL)) return(0);
5642 /* nodes need to be in the same document */
5643 if (ancestor->doc != node->doc) return(0);
5644 /* avoid searching if ancestor or node is the root node */
5645 if (ancestor == (xmlNodePtr) node->doc) return(1);
5646 if (node == (xmlNodePtr) ancestor->doc) return(0);
5647 while (node->parent != NULL) {
5648 if (node->parent == ancestor)
5649 return(1);
5650 node = node->parent;
5651 }
5652 return(0);
5653}
5654
5655/**
5656 * xmlXPathNextPreceding:
5657 * @ctxt: the XPath Parser context
5658 * @cur: the current node in the traversal
5659 *
5660 * Traversal function for the "preceding" direction
5661 * the preceding axis contains all nodes in the same document as the context
5662 * node that are before the context node in document order, excluding any
5663 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5664 * ordered in reverse document order
5665 *
5666 * Returns the next element following that axis
5667 */
5668xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005669xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5670{
Owen Taylor3473f882001-02-23 17:55:21 +00005671 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005672 cur = ctxt->context->node;
5673 if (cur == NULL)
5674 return (NULL);
5675 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5676 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005677 do {
5678 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005679 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5680 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005681 }
5682
5683 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005684 if (cur == NULL)
5685 return (NULL);
5686 if (cur == ctxt->context->doc->children)
5687 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005688 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005689 return (cur);
5690}
5691
5692/**
5693 * xmlXPathNextPrecedingInternal:
5694 * @ctxt: the XPath Parser context
5695 * @cur: the current node in the traversal
5696 *
5697 * Traversal function for the "preceding" direction
5698 * the preceding axis contains all nodes in the same document as the context
5699 * node that are before the context node in document order, excluding any
5700 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5701 * ordered in reverse document order
5702 * This is a faster implementation but internal only since it requires a
5703 * state kept in the parser context: ctxt->ancestor.
5704 *
5705 * Returns the next element following that axis
5706 */
5707static xmlNodePtr
5708xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5709 xmlNodePtr cur)
5710{
5711 if (cur == NULL) {
5712 cur = ctxt->context->node;
5713 if (cur == NULL)
5714 return (NULL);
5715 ctxt->ancestor = cur->parent;
5716 }
5717 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5718 cur = cur->prev;
5719 while (cur->prev == NULL) {
5720 cur = cur->parent;
5721 if (cur == NULL)
5722 return (NULL);
5723 if (cur == ctxt->context->doc->children)
5724 return (NULL);
5725 if (cur != ctxt->ancestor)
5726 return (cur);
5727 ctxt->ancestor = cur->parent;
5728 }
5729 cur = cur->prev;
5730 while (cur->last != NULL)
5731 cur = cur->last;
5732 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005733}
5734
5735/**
5736 * xmlXPathNextNamespace:
5737 * @ctxt: the XPath Parser context
5738 * @cur: the current attribute in the traversal
5739 *
5740 * Traversal function for the "namespace" direction
5741 * the namespace axis contains the namespace nodes of the context node;
5742 * the order of nodes on this axis is implementation-defined; the axis will
5743 * be empty unless the context node is an element
5744 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005745 * We keep the XML namespace node at the end of the list.
5746 *
Owen Taylor3473f882001-02-23 17:55:21 +00005747 * Returns the next element following that axis
5748 */
5749xmlNodePtr
5750xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5751 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00005752 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005753 if (ctxt->context->tmpNsList != NULL)
5754 xmlFree(ctxt->context->tmpNsList);
5755 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005756 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005757 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005758 if (ctxt->context->tmpNsList != NULL) {
5759 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
5760 ctxt->context->tmpNsNr++;
5761 }
5762 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005763 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005764 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00005765 if (ctxt->context->tmpNsNr > 0) {
5766 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
5767 } else {
5768 if (ctxt->context->tmpNsList != NULL)
5769 xmlFree(ctxt->context->tmpNsList);
5770 ctxt->context->tmpNsList = NULL;
5771 return(NULL);
5772 }
Owen Taylor3473f882001-02-23 17:55:21 +00005773}
5774
5775/**
5776 * xmlXPathNextAttribute:
5777 * @ctxt: the XPath Parser context
5778 * @cur: the current attribute in the traversal
5779 *
5780 * Traversal function for the "attribute" direction
5781 * TODO: support DTD inherited default attributes
5782 *
5783 * Returns the next element following that axis
5784 */
5785xmlNodePtr
5786xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005787 if (ctxt->context->node == NULL)
5788 return(NULL);
5789 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5790 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005791 if (cur == NULL) {
5792 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5793 return(NULL);
5794 return((xmlNodePtr)ctxt->context->node->properties);
5795 }
5796 return((xmlNodePtr)cur->next);
5797}
5798
5799/************************************************************************
5800 * *
5801 * NodeTest Functions *
5802 * *
5803 ************************************************************************/
5804
Owen Taylor3473f882001-02-23 17:55:21 +00005805#define IS_FUNCTION 200
5806
Owen Taylor3473f882001-02-23 17:55:21 +00005807
5808/************************************************************************
5809 * *
5810 * Implicit tree core function library *
5811 * *
5812 ************************************************************************/
5813
5814/**
5815 * xmlXPathRoot:
5816 * @ctxt: the XPath Parser context
5817 *
5818 * Initialize the context to the root of the document
5819 */
5820void
5821xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5822 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5823 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5824}
5825
5826/************************************************************************
5827 * *
5828 * The explicit core function library *
5829 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5830 * *
5831 ************************************************************************/
5832
5833
5834/**
5835 * xmlXPathLastFunction:
5836 * @ctxt: the XPath Parser context
5837 * @nargs: the number of arguments
5838 *
5839 * Implement the last() XPath function
5840 * number last()
5841 * The last function returns the number of nodes in the context node list.
5842 */
5843void
5844xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5845 CHECK_ARITY(0);
5846 if (ctxt->context->contextSize >= 0) {
5847 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5848#ifdef DEBUG_EXPR
5849 xmlGenericError(xmlGenericErrorContext,
5850 "last() : %d\n", ctxt->context->contextSize);
5851#endif
5852 } else {
5853 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5854 }
5855}
5856
5857/**
5858 * xmlXPathPositionFunction:
5859 * @ctxt: the XPath Parser context
5860 * @nargs: the number of arguments
5861 *
5862 * Implement the position() XPath function
5863 * number position()
5864 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005865 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00005866 * will be equal to last().
5867 */
5868void
5869xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5870 CHECK_ARITY(0);
5871 if (ctxt->context->proximityPosition >= 0) {
5872 valuePush(ctxt,
5873 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5874#ifdef DEBUG_EXPR
5875 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5876 ctxt->context->proximityPosition);
5877#endif
5878 } else {
5879 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5880 }
5881}
5882
5883/**
5884 * xmlXPathCountFunction:
5885 * @ctxt: the XPath Parser context
5886 * @nargs: the number of arguments
5887 *
5888 * Implement the count() XPath function
5889 * number count(node-set)
5890 */
5891void
5892xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5893 xmlXPathObjectPtr cur;
5894
5895 CHECK_ARITY(1);
5896 if ((ctxt->value == NULL) ||
5897 ((ctxt->value->type != XPATH_NODESET) &&
5898 (ctxt->value->type != XPATH_XSLT_TREE)))
5899 XP_ERROR(XPATH_INVALID_TYPE);
5900 cur = valuePop(ctxt);
5901
Daniel Veillard911f49a2001-04-07 15:39:35 +00005902 if ((cur == NULL) || (cur->nodesetval == NULL))
5903 valuePush(ctxt, xmlXPathNewFloat((double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00005904 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00005905 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00005906 } else {
5907 if ((cur->nodesetval->nodeNr != 1) ||
5908 (cur->nodesetval->nodeTab == NULL)) {
5909 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5910 } else {
5911 xmlNodePtr tmp;
5912 int i = 0;
5913
5914 tmp = cur->nodesetval->nodeTab[0];
5915 if (tmp != NULL) {
5916 tmp = tmp->children;
5917 while (tmp != NULL) {
5918 tmp = tmp->next;
5919 i++;
5920 }
5921 }
5922 valuePush(ctxt, xmlXPathNewFloat((double) i));
5923 }
5924 }
Owen Taylor3473f882001-02-23 17:55:21 +00005925 xmlXPathFreeObject(cur);
5926}
5927
5928/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005929 * xmlXPathGetElementsByIds:
5930 * @doc: the document
5931 * @ids: a whitespace separated list of IDs
5932 *
5933 * Selects elements by their unique ID.
5934 *
5935 * Returns a node-set of selected elements.
5936 */
5937static xmlNodeSetPtr
5938xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5939 xmlNodeSetPtr ret;
5940 const xmlChar *cur = ids;
5941 xmlChar *ID;
5942 xmlAttrPtr attr;
5943 xmlNodePtr elem = NULL;
5944
5945 ret = xmlXPathNodeSetCreate(NULL);
5946
5947 while (IS_BLANK(*cur)) cur++;
5948 while (*cur != 0) {
Daniel Veillarde209b332003-03-26 21:40:13 +00005949 while ((!IS_BLANK(*cur)) && (*cur != 0))
5950 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005951
5952 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00005953 if (ID != NULL) {
5954 if (xmlValidateNCName(ID, 1) == 0) {
5955 attr = xmlGetID(doc, ID);
5956 if (attr != NULL) {
5957 if (attr->type == XML_ATTRIBUTE_NODE)
5958 elem = attr->parent;
5959 else if (attr->type == XML_ELEMENT_NODE)
5960 elem = (xmlNodePtr) attr;
5961 else
5962 elem = NULL;
5963 if (elem != NULL)
5964 xmlXPathNodeSetAdd(ret, elem);
5965 }
5966 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005967 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00005968 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005969
5970 while (IS_BLANK(*cur)) cur++;
5971 ids = cur;
5972 }
5973 return(ret);
5974}
5975
5976/**
Owen Taylor3473f882001-02-23 17:55:21 +00005977 * xmlXPathIdFunction:
5978 * @ctxt: the XPath Parser context
5979 * @nargs: the number of arguments
5980 *
5981 * Implement the id() XPath function
5982 * node-set id(object)
5983 * The id function selects elements by their unique ID
5984 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
5985 * then the result is the union of the result of applying id to the
5986 * string value of each of the nodes in the argument node-set. When the
5987 * argument to id is of any other type, the argument is converted to a
5988 * string as if by a call to the string function; the string is split
5989 * into a whitespace-separated list of tokens (whitespace is any sequence
5990 * of characters matching the production S); the result is a node-set
5991 * containing the elements in the same document as the context node that
5992 * have a unique ID equal to any of the tokens in the list.
5993 */
5994void
5995xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005996 xmlChar *tokens;
5997 xmlNodeSetPtr ret;
5998 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00005999
6000 CHECK_ARITY(1);
6001 obj = valuePop(ctxt);
6002 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00006003 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006004 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00006005 int i;
6006
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006007 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006008
Daniel Veillard911f49a2001-04-07 15:39:35 +00006009 if (obj->nodesetval != NULL) {
6010 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006011 tokens =
6012 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
6013 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
6014 ret = xmlXPathNodeSetMerge(ret, ns);
6015 xmlXPathFreeNodeSet(ns);
6016 if (tokens != NULL)
6017 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006018 }
Owen Taylor3473f882001-02-23 17:55:21 +00006019 }
6020
6021 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006022 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006023 return;
6024 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006025 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00006026
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006027 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
6028 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006029
Owen Taylor3473f882001-02-23 17:55:21 +00006030 xmlXPathFreeObject(obj);
6031 return;
6032}
6033
6034/**
6035 * xmlXPathLocalNameFunction:
6036 * @ctxt: the XPath Parser context
6037 * @nargs: the number of arguments
6038 *
6039 * Implement the local-name() XPath function
6040 * string local-name(node-set?)
6041 * The local-name function returns a string containing the local part
6042 * of the name of the node in the argument node-set that is first in
6043 * document order. If the node-set is empty or the first node has no
6044 * name, an empty string is returned. If the argument is omitted it
6045 * defaults to the context node.
6046 */
6047void
6048xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6049 xmlXPathObjectPtr cur;
6050
6051 if (nargs == 0) {
6052 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6053 nargs = 1;
6054 }
6055
6056 CHECK_ARITY(1);
6057 if ((ctxt->value == NULL) ||
6058 ((ctxt->value->type != XPATH_NODESET) &&
6059 (ctxt->value->type != XPATH_XSLT_TREE)))
6060 XP_ERROR(XPATH_INVALID_TYPE);
6061 cur = valuePop(ctxt);
6062
Daniel Veillard911f49a2001-04-07 15:39:35 +00006063 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006064 valuePush(ctxt, xmlXPathNewCString(""));
6065 } else {
6066 int i = 0; /* Should be first in document order !!!!! */
6067 switch (cur->nodesetval->nodeTab[i]->type) {
6068 case XML_ELEMENT_NODE:
6069 case XML_ATTRIBUTE_NODE:
6070 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006071 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6072 valuePush(ctxt, xmlXPathNewCString(""));
6073 else
6074 valuePush(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006075 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
6076 break;
6077 case XML_NAMESPACE_DECL:
6078 valuePush(ctxt, xmlXPathNewString(
6079 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
6080 break;
6081 default:
6082 valuePush(ctxt, xmlXPathNewCString(""));
6083 }
6084 }
6085 xmlXPathFreeObject(cur);
6086}
6087
6088/**
6089 * xmlXPathNamespaceURIFunction:
6090 * @ctxt: the XPath Parser context
6091 * @nargs: the number of arguments
6092 *
6093 * Implement the namespace-uri() XPath function
6094 * string namespace-uri(node-set?)
6095 * The namespace-uri function returns a string containing the
6096 * namespace URI of the expanded name of the node in the argument
6097 * node-set that is first in document order. If the node-set is empty,
6098 * the first node has no name, or the expanded name has no namespace
6099 * URI, an empty string is returned. If the argument is omitted it
6100 * defaults to the context node.
6101 */
6102void
6103xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6104 xmlXPathObjectPtr cur;
6105
6106 if (nargs == 0) {
6107 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6108 nargs = 1;
6109 }
6110 CHECK_ARITY(1);
6111 if ((ctxt->value == NULL) ||
6112 ((ctxt->value->type != XPATH_NODESET) &&
6113 (ctxt->value->type != XPATH_XSLT_TREE)))
6114 XP_ERROR(XPATH_INVALID_TYPE);
6115 cur = valuePop(ctxt);
6116
Daniel Veillard911f49a2001-04-07 15:39:35 +00006117 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006118 valuePush(ctxt, xmlXPathNewCString(""));
6119 } else {
6120 int i = 0; /* Should be first in document order !!!!! */
6121 switch (cur->nodesetval->nodeTab[i]->type) {
6122 case XML_ELEMENT_NODE:
6123 case XML_ATTRIBUTE_NODE:
6124 if (cur->nodesetval->nodeTab[i]->ns == NULL)
6125 valuePush(ctxt, xmlXPathNewCString(""));
6126 else
6127 valuePush(ctxt, xmlXPathNewString(
6128 cur->nodesetval->nodeTab[i]->ns->href));
6129 break;
6130 default:
6131 valuePush(ctxt, xmlXPathNewCString(""));
6132 }
6133 }
6134 xmlXPathFreeObject(cur);
6135}
6136
6137/**
6138 * xmlXPathNameFunction:
6139 * @ctxt: the XPath Parser context
6140 * @nargs: the number of arguments
6141 *
6142 * Implement the name() XPath function
6143 * string name(node-set?)
6144 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006145 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00006146 * order. The QName must represent the name with respect to the namespace
6147 * declarations in effect on the node whose name is being represented.
6148 * Typically, this will be the form in which the name occurred in the XML
6149 * source. This need not be the case if there are namespace declarations
6150 * in effect on the node that associate multiple prefixes with the same
6151 * namespace. However, an implementation may include information about
6152 * the original prefix in its representation of nodes; in this case, an
6153 * implementation can ensure that the returned string is always the same
6154 * as the QName used in the XML source. If the argument it omitted it
6155 * defaults to the context node.
6156 * Libxml keep the original prefix so the "real qualified name" used is
6157 * returned.
6158 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006159static void
Daniel Veillard04383752001-07-08 14:27:15 +00006160xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
6161{
Owen Taylor3473f882001-02-23 17:55:21 +00006162 xmlXPathObjectPtr cur;
6163
6164 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00006165 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6166 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006167 }
6168
6169 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00006170 if ((ctxt->value == NULL) ||
6171 ((ctxt->value->type != XPATH_NODESET) &&
6172 (ctxt->value->type != XPATH_XSLT_TREE)))
6173 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006174 cur = valuePop(ctxt);
6175
Daniel Veillard911f49a2001-04-07 15:39:35 +00006176 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006177 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00006178 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006179 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00006180
Daniel Veillard04383752001-07-08 14:27:15 +00006181 switch (cur->nodesetval->nodeTab[i]->type) {
6182 case XML_ELEMENT_NODE:
6183 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006184 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6185 valuePush(ctxt, xmlXPathNewCString(""));
6186 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6187 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006188 valuePush(ctxt,
Daniel Veillardc00cda82003-04-07 10:22:39 +00006189 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
Daniel Veillard04383752001-07-08 14:27:15 +00006190
Daniel Veillard652d8a92003-02-04 19:28:49 +00006191 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006192 xmlChar *fullname;
6193
6194 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
6195 cur->nodesetval->nodeTab[i]->ns->prefix,
6196 NULL, 0);
6197 if (fullname == cur->nodesetval->nodeTab[i]->name)
6198 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
6199 if (fullname == NULL) {
6200 XP_ERROR(XPATH_MEMORY_ERROR);
6201 }
6202 valuePush(ctxt, xmlXPathWrapString(fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00006203 }
6204 break;
6205 default:
6206 valuePush(ctxt,
6207 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6208 xmlXPathLocalNameFunction(ctxt, 1);
6209 }
Owen Taylor3473f882001-02-23 17:55:21 +00006210 }
6211 xmlXPathFreeObject(cur);
6212}
6213
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006214
6215/**
Owen Taylor3473f882001-02-23 17:55:21 +00006216 * xmlXPathStringFunction:
6217 * @ctxt: the XPath Parser context
6218 * @nargs: the number of arguments
6219 *
6220 * Implement the string() XPath function
6221 * string string(object?)
6222 * he string function converts an object to a string as follows:
6223 * - A node-set is converted to a string by returning the value of
6224 * the node in the node-set that is first in document order.
6225 * If the node-set is empty, an empty string is returned.
6226 * - A number is converted to a string as follows
6227 * + NaN is converted to the string NaN
6228 * + positive zero is converted to the string 0
6229 * + negative zero is converted to the string 0
6230 * + positive infinity is converted to the string Infinity
6231 * + negative infinity is converted to the string -Infinity
6232 * + if the number is an integer, the number is represented in
6233 * decimal form as a Number with no decimal point and no leading
6234 * zeros, preceded by a minus sign (-) if the number is negative
6235 * + otherwise, the number is represented in decimal form as a
6236 * Number including a decimal point with at least one digit
6237 * before the decimal point and at least one digit after the
6238 * decimal point, preceded by a minus sign (-) if the number
6239 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006240 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00006241 * before the decimal point; beyond the one required digit
6242 * after the decimal point there must be as many, but only as
6243 * many, more digits as are needed to uniquely distinguish the
6244 * number from all other IEEE 754 numeric values.
6245 * - The boolean false value is converted to the string false.
6246 * The boolean true value is converted to the string true.
6247 *
6248 * If the argument is omitted, it defaults to a node-set with the
6249 * context node as its only member.
6250 */
6251void
6252xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6253 xmlXPathObjectPtr cur;
6254
6255 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006256 valuePush(ctxt,
6257 xmlXPathWrapString(
6258 xmlXPathCastNodeToString(ctxt->context->node)));
6259 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006260 }
6261
6262 CHECK_ARITY(1);
6263 cur = valuePop(ctxt);
6264 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006265 cur = xmlXPathConvertString(cur);
6266 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006267}
6268
6269/**
6270 * xmlXPathStringLengthFunction:
6271 * @ctxt: the XPath Parser context
6272 * @nargs: the number of arguments
6273 *
6274 * Implement the string-length() XPath function
6275 * number string-length(string?)
6276 * The string-length returns the number of characters in the string
6277 * (see [3.6 Strings]). If the argument is omitted, it defaults to
6278 * the context node converted to a string, in other words the value
6279 * of the context node.
6280 */
6281void
6282xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6283 xmlXPathObjectPtr cur;
6284
6285 if (nargs == 0) {
6286 if (ctxt->context->node == NULL) {
6287 valuePush(ctxt, xmlXPathNewFloat(0));
6288 } else {
6289 xmlChar *content;
6290
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006291 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006292 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00006293 xmlFree(content);
6294 }
6295 return;
6296 }
6297 CHECK_ARITY(1);
6298 CAST_TO_STRING;
6299 CHECK_TYPE(XPATH_STRING);
6300 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006301 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00006302 xmlXPathFreeObject(cur);
6303}
6304
6305/**
6306 * xmlXPathConcatFunction:
6307 * @ctxt: the XPath Parser context
6308 * @nargs: the number of arguments
6309 *
6310 * Implement the concat() XPath function
6311 * string concat(string, string, string*)
6312 * The concat function returns the concatenation of its arguments.
6313 */
6314void
6315xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6316 xmlXPathObjectPtr cur, newobj;
6317 xmlChar *tmp;
6318
6319 if (nargs < 2) {
6320 CHECK_ARITY(2);
6321 }
6322
6323 CAST_TO_STRING;
6324 cur = valuePop(ctxt);
6325 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6326 xmlXPathFreeObject(cur);
6327 return;
6328 }
6329 nargs--;
6330
6331 while (nargs > 0) {
6332 CAST_TO_STRING;
6333 newobj = valuePop(ctxt);
6334 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6335 xmlXPathFreeObject(newobj);
6336 xmlXPathFreeObject(cur);
6337 XP_ERROR(XPATH_INVALID_TYPE);
6338 }
6339 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6340 newobj->stringval = cur->stringval;
6341 cur->stringval = tmp;
6342
6343 xmlXPathFreeObject(newobj);
6344 nargs--;
6345 }
6346 valuePush(ctxt, cur);
6347}
6348
6349/**
6350 * xmlXPathContainsFunction:
6351 * @ctxt: the XPath Parser context
6352 * @nargs: the number of arguments
6353 *
6354 * Implement the contains() XPath function
6355 * boolean contains(string, string)
6356 * The contains function returns true if the first argument string
6357 * contains the second argument string, and otherwise returns false.
6358 */
6359void
6360xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6361 xmlXPathObjectPtr hay, needle;
6362
6363 CHECK_ARITY(2);
6364 CAST_TO_STRING;
6365 CHECK_TYPE(XPATH_STRING);
6366 needle = valuePop(ctxt);
6367 CAST_TO_STRING;
6368 hay = valuePop(ctxt);
6369 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6370 xmlXPathFreeObject(hay);
6371 xmlXPathFreeObject(needle);
6372 XP_ERROR(XPATH_INVALID_TYPE);
6373 }
6374 if (xmlStrstr(hay->stringval, needle->stringval))
6375 valuePush(ctxt, xmlXPathNewBoolean(1));
6376 else
6377 valuePush(ctxt, xmlXPathNewBoolean(0));
6378 xmlXPathFreeObject(hay);
6379 xmlXPathFreeObject(needle);
6380}
6381
6382/**
6383 * xmlXPathStartsWithFunction:
6384 * @ctxt: the XPath Parser context
6385 * @nargs: the number of arguments
6386 *
6387 * Implement the starts-with() XPath function
6388 * boolean starts-with(string, string)
6389 * The starts-with function returns true if the first argument string
6390 * starts with the second argument string, and otherwise returns false.
6391 */
6392void
6393xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6394 xmlXPathObjectPtr hay, needle;
6395 int n;
6396
6397 CHECK_ARITY(2);
6398 CAST_TO_STRING;
6399 CHECK_TYPE(XPATH_STRING);
6400 needle = valuePop(ctxt);
6401 CAST_TO_STRING;
6402 hay = valuePop(ctxt);
6403 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6404 xmlXPathFreeObject(hay);
6405 xmlXPathFreeObject(needle);
6406 XP_ERROR(XPATH_INVALID_TYPE);
6407 }
6408 n = xmlStrlen(needle->stringval);
6409 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6410 valuePush(ctxt, xmlXPathNewBoolean(0));
6411 else
6412 valuePush(ctxt, xmlXPathNewBoolean(1));
6413 xmlXPathFreeObject(hay);
6414 xmlXPathFreeObject(needle);
6415}
6416
6417/**
6418 * xmlXPathSubstringFunction:
6419 * @ctxt: the XPath Parser context
6420 * @nargs: the number of arguments
6421 *
6422 * Implement the substring() XPath function
6423 * string substring(string, number, number?)
6424 * The substring function returns the substring of the first argument
6425 * starting at the position specified in the second argument with
6426 * length specified in the third argument. For example,
6427 * substring("12345",2,3) returns "234". If the third argument is not
6428 * specified, it returns the substring starting at the position specified
6429 * in the second argument and continuing to the end of the string. For
6430 * example, substring("12345",2) returns "2345". More precisely, each
6431 * character in the string (see [3.6 Strings]) is considered to have a
6432 * numeric position: the position of the first character is 1, the position
6433 * of the second character is 2 and so on. The returned substring contains
6434 * those characters for which the position of the character is greater than
6435 * or equal to the second argument and, if the third argument is specified,
6436 * less than the sum of the second and third arguments; the comparisons
6437 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6438 * - substring("12345", 1.5, 2.6) returns "234"
6439 * - substring("12345", 0, 3) returns "12"
6440 * - substring("12345", 0 div 0, 3) returns ""
6441 * - substring("12345", 1, 0 div 0) returns ""
6442 * - substring("12345", -42, 1 div 0) returns "12345"
6443 * - substring("12345", -1 div 0, 1 div 0) returns ""
6444 */
6445void
6446xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6447 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006448 double le=0, in;
6449 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006450 xmlChar *ret;
6451
Owen Taylor3473f882001-02-23 17:55:21 +00006452 if (nargs < 2) {
6453 CHECK_ARITY(2);
6454 }
6455 if (nargs > 3) {
6456 CHECK_ARITY(3);
6457 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006458 /*
6459 * take care of possible last (position) argument
6460 */
Owen Taylor3473f882001-02-23 17:55:21 +00006461 if (nargs == 3) {
6462 CAST_TO_NUMBER;
6463 CHECK_TYPE(XPATH_NUMBER);
6464 len = valuePop(ctxt);
6465 le = len->floatval;
6466 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006467 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006468
Owen Taylor3473f882001-02-23 17:55:21 +00006469 CAST_TO_NUMBER;
6470 CHECK_TYPE(XPATH_NUMBER);
6471 start = valuePop(ctxt);
6472 in = start->floatval;
6473 xmlXPathFreeObject(start);
6474 CAST_TO_STRING;
6475 CHECK_TYPE(XPATH_STRING);
6476 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006477 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006478
Daniel Veillard97ac1312001-05-30 19:14:17 +00006479 /*
6480 * If last pos not present, calculate last position
6481 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006482 if (nargs != 3) {
6483 le = (double)m;
6484 if (in < 1.0)
6485 in = 1.0;
6486 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006487
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006488 /* Need to check for the special cases where either
6489 * the index is NaN, the length is NaN, or both
6490 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00006491 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006492 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006493 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00006494 * To meet the requirements of the spec, the arguments
6495 * must be converted to integer format before
6496 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006497 *
Daniel Veillard9e412302002-06-10 15:59:44 +00006498 * First we go to integer form, rounding up
6499 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006500 */
6501 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00006502 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00006503
Daniel Veillard9e412302002-06-10 15:59:44 +00006504 if (xmlXPathIsInf(le) == 1) {
6505 l = m;
6506 if (i < 1)
6507 i = 1;
6508 }
6509 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
6510 l = 0;
6511 else {
6512 l = (int) le;
6513 if (((double)l)+0.5 <= le) l++;
6514 }
6515
6516 /* Now we normalize inidices */
6517 i -= 1;
6518 l += i;
6519 if (i < 0)
6520 i = 0;
6521 if (l > m)
6522 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00006523
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006524 /* number of chars to copy */
6525 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00006526
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006527 ret = xmlUTF8Strsub(str->stringval, i, l);
6528 }
6529 else {
6530 ret = NULL;
6531 }
6532
Owen Taylor3473f882001-02-23 17:55:21 +00006533 if (ret == NULL)
6534 valuePush(ctxt, xmlXPathNewCString(""));
6535 else {
6536 valuePush(ctxt, xmlXPathNewString(ret));
6537 xmlFree(ret);
6538 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006539
Owen Taylor3473f882001-02-23 17:55:21 +00006540 xmlXPathFreeObject(str);
6541}
6542
6543/**
6544 * xmlXPathSubstringBeforeFunction:
6545 * @ctxt: the XPath Parser context
6546 * @nargs: the number of arguments
6547 *
6548 * Implement the substring-before() XPath function
6549 * string substring-before(string, string)
6550 * The substring-before function returns the substring of the first
6551 * argument string that precedes the first occurrence of the second
6552 * argument string in the first argument string, or the empty string
6553 * if the first argument string does not contain the second argument
6554 * string. For example, substring-before("1999/04/01","/") returns 1999.
6555 */
6556void
6557xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6558 xmlXPathObjectPtr str;
6559 xmlXPathObjectPtr find;
6560 xmlBufferPtr target;
6561 const xmlChar *point;
6562 int offset;
6563
6564 CHECK_ARITY(2);
6565 CAST_TO_STRING;
6566 find = valuePop(ctxt);
6567 CAST_TO_STRING;
6568 str = valuePop(ctxt);
6569
6570 target = xmlBufferCreate();
6571 if (target) {
6572 point = xmlStrstr(str->stringval, find->stringval);
6573 if (point) {
6574 offset = (int)(point - str->stringval);
6575 xmlBufferAdd(target, str->stringval, offset);
6576 }
6577 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6578 xmlBufferFree(target);
6579 }
6580
6581 xmlXPathFreeObject(str);
6582 xmlXPathFreeObject(find);
6583}
6584
6585/**
6586 * xmlXPathSubstringAfterFunction:
6587 * @ctxt: the XPath Parser context
6588 * @nargs: the number of arguments
6589 *
6590 * Implement the substring-after() XPath function
6591 * string substring-after(string, string)
6592 * The substring-after function returns the substring of the first
6593 * argument string that follows the first occurrence of the second
6594 * argument string in the first argument string, or the empty stringi
6595 * if the first argument string does not contain the second argument
6596 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6597 * and substring-after("1999/04/01","19") returns 99/04/01.
6598 */
6599void
6600xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6601 xmlXPathObjectPtr str;
6602 xmlXPathObjectPtr find;
6603 xmlBufferPtr target;
6604 const xmlChar *point;
6605 int offset;
6606
6607 CHECK_ARITY(2);
6608 CAST_TO_STRING;
6609 find = valuePop(ctxt);
6610 CAST_TO_STRING;
6611 str = valuePop(ctxt);
6612
6613 target = xmlBufferCreate();
6614 if (target) {
6615 point = xmlStrstr(str->stringval, find->stringval);
6616 if (point) {
6617 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6618 xmlBufferAdd(target, &str->stringval[offset],
6619 xmlStrlen(str->stringval) - offset);
6620 }
6621 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6622 xmlBufferFree(target);
6623 }
6624
6625 xmlXPathFreeObject(str);
6626 xmlXPathFreeObject(find);
6627}
6628
6629/**
6630 * xmlXPathNormalizeFunction:
6631 * @ctxt: the XPath Parser context
6632 * @nargs: the number of arguments
6633 *
6634 * Implement the normalize-space() XPath function
6635 * string normalize-space(string?)
6636 * The normalize-space function returns the argument string with white
6637 * space normalized by stripping leading and trailing whitespace
6638 * and replacing sequences of whitespace characters by a single
6639 * space. Whitespace characters are the same allowed by the S production
6640 * in XML. If the argument is omitted, it defaults to the context
6641 * node converted to a string, in other words the value of the context node.
6642 */
6643void
6644xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6645 xmlXPathObjectPtr obj = NULL;
6646 xmlChar *source = NULL;
6647 xmlBufferPtr target;
6648 xmlChar blank;
6649
6650 if (nargs == 0) {
6651 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006652 valuePush(ctxt,
6653 xmlXPathWrapString(
6654 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006655 nargs = 1;
6656 }
6657
6658 CHECK_ARITY(1);
6659 CAST_TO_STRING;
6660 CHECK_TYPE(XPATH_STRING);
6661 obj = valuePop(ctxt);
6662 source = obj->stringval;
6663
6664 target = xmlBufferCreate();
6665 if (target && source) {
6666
6667 /* Skip leading whitespaces */
6668 while (IS_BLANK(*source))
6669 source++;
6670
6671 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6672 blank = 0;
6673 while (*source) {
6674 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006675 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006676 } else {
6677 if (blank) {
6678 xmlBufferAdd(target, &blank, 1);
6679 blank = 0;
6680 }
6681 xmlBufferAdd(target, source, 1);
6682 }
6683 source++;
6684 }
6685
6686 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6687 xmlBufferFree(target);
6688 }
6689 xmlXPathFreeObject(obj);
6690}
6691
6692/**
6693 * xmlXPathTranslateFunction:
6694 * @ctxt: the XPath Parser context
6695 * @nargs: the number of arguments
6696 *
6697 * Implement the translate() XPath function
6698 * string translate(string, string, string)
6699 * The translate function returns the first argument string with
6700 * occurrences of characters in the second argument string replaced
6701 * by the character at the corresponding position in the third argument
6702 * string. For example, translate("bar","abc","ABC") returns the string
6703 * BAr. If there is a character in the second argument string with no
6704 * character at a corresponding position in the third argument string
6705 * (because the second argument string is longer than the third argument
6706 * string), then occurrences of that character in the first argument
6707 * string are removed. For example, translate("--aaa--","abc-","ABC")
6708 * returns "AAA". If a character occurs more than once in second
6709 * argument string, then the first occurrence determines the replacement
6710 * character. If the third argument string is longer than the second
6711 * argument string, then excess characters are ignored.
6712 */
6713void
6714xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006715 xmlXPathObjectPtr str;
6716 xmlXPathObjectPtr from;
6717 xmlXPathObjectPtr to;
6718 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006719 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006720 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006721 xmlChar *point;
6722 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006723
Daniel Veillarde043ee12001-04-16 14:08:07 +00006724 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006725
Daniel Veillarde043ee12001-04-16 14:08:07 +00006726 CAST_TO_STRING;
6727 to = valuePop(ctxt);
6728 CAST_TO_STRING;
6729 from = valuePop(ctxt);
6730 CAST_TO_STRING;
6731 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006732
Daniel Veillarde043ee12001-04-16 14:08:07 +00006733 target = xmlBufferCreate();
6734 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006735 max = xmlUTF8Strlen(to->stringval);
6736 for (cptr = str->stringval; (ch=*cptr); ) {
6737 offset = xmlUTF8Strloc(from->stringval, cptr);
6738 if (offset >= 0) {
6739 if (offset < max) {
6740 point = xmlUTF8Strpos(to->stringval, offset);
6741 if (point)
6742 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6743 }
6744 } else
6745 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6746
6747 /* Step to next character in input */
6748 cptr++;
6749 if ( ch & 0x80 ) {
6750 /* if not simple ascii, verify proper format */
6751 if ( (ch & 0xc0) != 0xc0 ) {
6752 xmlGenericError(xmlGenericErrorContext,
6753 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6754 break;
6755 }
6756 /* then skip over remaining bytes for this char */
6757 while ( (ch <<= 1) & 0x80 )
6758 if ( (*cptr++ & 0xc0) != 0x80 ) {
6759 xmlGenericError(xmlGenericErrorContext,
6760 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6761 break;
6762 }
6763 if (ch & 0x80) /* must have had error encountered */
6764 break;
6765 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006766 }
Owen Taylor3473f882001-02-23 17:55:21 +00006767 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006768 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6769 xmlBufferFree(target);
6770 xmlXPathFreeObject(str);
6771 xmlXPathFreeObject(from);
6772 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006773}
6774
6775/**
6776 * xmlXPathBooleanFunction:
6777 * @ctxt: the XPath Parser context
6778 * @nargs: the number of arguments
6779 *
6780 * Implement the boolean() XPath function
6781 * boolean boolean(object)
6782 * he boolean function converts its argument to a boolean as follows:
6783 * - a number is true if and only if it is neither positive or
6784 * negative zero nor NaN
6785 * - a node-set is true if and only if it is non-empty
6786 * - a string is true if and only if its length is non-zero
6787 */
6788void
6789xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6790 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006791
6792 CHECK_ARITY(1);
6793 cur = valuePop(ctxt);
6794 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006795 cur = xmlXPathConvertBoolean(cur);
6796 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006797}
6798
6799/**
6800 * xmlXPathNotFunction:
6801 * @ctxt: the XPath Parser context
6802 * @nargs: the number of arguments
6803 *
6804 * Implement the not() XPath function
6805 * boolean not(boolean)
6806 * The not function returns true if its argument is false,
6807 * and false otherwise.
6808 */
6809void
6810xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6811 CHECK_ARITY(1);
6812 CAST_TO_BOOLEAN;
6813 CHECK_TYPE(XPATH_BOOLEAN);
6814 ctxt->value->boolval = ! ctxt->value->boolval;
6815}
6816
6817/**
6818 * xmlXPathTrueFunction:
6819 * @ctxt: the XPath Parser context
6820 * @nargs: the number of arguments
6821 *
6822 * Implement the true() XPath function
6823 * boolean true()
6824 */
6825void
6826xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6827 CHECK_ARITY(0);
6828 valuePush(ctxt, xmlXPathNewBoolean(1));
6829}
6830
6831/**
6832 * xmlXPathFalseFunction:
6833 * @ctxt: the XPath Parser context
6834 * @nargs: the number of arguments
6835 *
6836 * Implement the false() XPath function
6837 * boolean false()
6838 */
6839void
6840xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6841 CHECK_ARITY(0);
6842 valuePush(ctxt, xmlXPathNewBoolean(0));
6843}
6844
6845/**
6846 * xmlXPathLangFunction:
6847 * @ctxt: the XPath Parser context
6848 * @nargs: the number of arguments
6849 *
6850 * Implement the lang() XPath function
6851 * boolean lang(string)
6852 * The lang function returns true or false depending on whether the
6853 * language of the context node as specified by xml:lang attributes
6854 * is the same as or is a sublanguage of the language specified by
6855 * the argument string. The language of the context node is determined
6856 * by the value of the xml:lang attribute on the context node, or, if
6857 * the context node has no xml:lang attribute, by the value of the
6858 * xml:lang attribute on the nearest ancestor of the context node that
6859 * has an xml:lang attribute. If there is no such attribute, then lang
6860 * returns false. If there is such an attribute, then lang returns
6861 * true if the attribute value is equal to the argument ignoring case,
6862 * or if there is some suffix starting with - such that the attribute
6863 * value is equal to the argument ignoring that suffix of the attribute
6864 * value and ignoring case.
6865 */
6866void
6867xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6868 xmlXPathObjectPtr val;
6869 const xmlChar *theLang;
6870 const xmlChar *lang;
6871 int ret = 0;
6872 int i;
6873
6874 CHECK_ARITY(1);
6875 CAST_TO_STRING;
6876 CHECK_TYPE(XPATH_STRING);
6877 val = valuePop(ctxt);
6878 lang = val->stringval;
6879 theLang = xmlNodeGetLang(ctxt->context->node);
6880 if ((theLang != NULL) && (lang != NULL)) {
6881 for (i = 0;lang[i] != 0;i++)
6882 if (toupper(lang[i]) != toupper(theLang[i]))
6883 goto not_equal;
6884 ret = 1;
6885 }
6886not_equal:
6887 xmlXPathFreeObject(val);
6888 valuePush(ctxt, xmlXPathNewBoolean(ret));
6889}
6890
6891/**
6892 * xmlXPathNumberFunction:
6893 * @ctxt: the XPath Parser context
6894 * @nargs: the number of arguments
6895 *
6896 * Implement the number() XPath function
6897 * number number(object?)
6898 */
6899void
6900xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6901 xmlXPathObjectPtr cur;
6902 double res;
6903
6904 if (nargs == 0) {
6905 if (ctxt->context->node == NULL) {
6906 valuePush(ctxt, xmlXPathNewFloat(0.0));
6907 } else {
6908 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6909
6910 res = xmlXPathStringEvalNumber(content);
6911 valuePush(ctxt, xmlXPathNewFloat(res));
6912 xmlFree(content);
6913 }
6914 return;
6915 }
6916
6917 CHECK_ARITY(1);
6918 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006919 cur = xmlXPathConvertNumber(cur);
6920 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006921}
6922
6923/**
6924 * xmlXPathSumFunction:
6925 * @ctxt: the XPath Parser context
6926 * @nargs: the number of arguments
6927 *
6928 * Implement the sum() XPath function
6929 * number sum(node-set)
6930 * The sum function returns the sum of the values of the nodes in
6931 * the argument node-set.
6932 */
6933void
6934xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6935 xmlXPathObjectPtr cur;
6936 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006937 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00006938
6939 CHECK_ARITY(1);
6940 if ((ctxt->value == NULL) ||
6941 ((ctxt->value->type != XPATH_NODESET) &&
6942 (ctxt->value->type != XPATH_XSLT_TREE)))
6943 XP_ERROR(XPATH_INVALID_TYPE);
6944 cur = valuePop(ctxt);
6945
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006946 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006947 valuePush(ctxt, xmlXPathNewFloat(0.0));
6948 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006949 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
6950 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006951 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006952 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00006953 }
6954 xmlXPathFreeObject(cur);
6955}
6956
6957/**
6958 * xmlXPathFloorFunction:
6959 * @ctxt: the XPath Parser context
6960 * @nargs: the number of arguments
6961 *
6962 * Implement the floor() XPath function
6963 * number floor(number)
6964 * The floor function returns the largest (closest to positive infinity)
6965 * number that is not greater than the argument and that is an integer.
6966 */
6967void
6968xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006969 double f;
6970
Owen Taylor3473f882001-02-23 17:55:21 +00006971 CHECK_ARITY(1);
6972 CAST_TO_NUMBER;
6973 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006974
6975 f = (double)((int) ctxt->value->floatval);
6976 if (f != ctxt->value->floatval) {
6977 if (ctxt->value->floatval > 0)
6978 ctxt->value->floatval = f;
6979 else
6980 ctxt->value->floatval = f - 1;
6981 }
Owen Taylor3473f882001-02-23 17:55:21 +00006982}
6983
6984/**
6985 * xmlXPathCeilingFunction:
6986 * @ctxt: the XPath Parser context
6987 * @nargs: the number of arguments
6988 *
6989 * Implement the ceiling() XPath function
6990 * number ceiling(number)
6991 * The ceiling function returns the smallest (closest to negative infinity)
6992 * number that is not less than the argument and that is an integer.
6993 */
6994void
6995xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6996 double f;
6997
6998 CHECK_ARITY(1);
6999 CAST_TO_NUMBER;
7000 CHECK_TYPE(XPATH_NUMBER);
7001
7002#if 0
7003 ctxt->value->floatval = ceil(ctxt->value->floatval);
7004#else
7005 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007006 if (f != ctxt->value->floatval) {
7007 if (ctxt->value->floatval > 0)
7008 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007009 else {
7010 if (ctxt->value->floatval < 0 && f == 0)
7011 ctxt->value->floatval = xmlXPathNZERO;
7012 else
7013 ctxt->value->floatval = f;
7014 }
7015
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007016 }
Owen Taylor3473f882001-02-23 17:55:21 +00007017#endif
7018}
7019
7020/**
7021 * xmlXPathRoundFunction:
7022 * @ctxt: the XPath Parser context
7023 * @nargs: the number of arguments
7024 *
7025 * Implement the round() XPath function
7026 * number round(number)
7027 * The round function returns the number that is closest to the
7028 * argument and that is an integer. If there are two such numbers,
7029 * then the one that is even is returned.
7030 */
7031void
7032xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7033 double f;
7034
7035 CHECK_ARITY(1);
7036 CAST_TO_NUMBER;
7037 CHECK_TYPE(XPATH_NUMBER);
7038
Daniel Veillardcda96922001-08-21 10:56:31 +00007039 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
7040 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
7041 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007042 (ctxt->value->floatval == 0.0))
7043 return;
7044
Owen Taylor3473f882001-02-23 17:55:21 +00007045 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007046 if (ctxt->value->floatval < 0) {
7047 if (ctxt->value->floatval < f - 0.5)
7048 ctxt->value->floatval = f - 1;
7049 else
7050 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007051 if (ctxt->value->floatval == 0)
7052 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007053 } else {
7054 if (ctxt->value->floatval < f + 0.5)
7055 ctxt->value->floatval = f;
7056 else
7057 ctxt->value->floatval = f + 1;
7058 }
Owen Taylor3473f882001-02-23 17:55:21 +00007059}
7060
7061/************************************************************************
7062 * *
7063 * The Parser *
7064 * *
7065 ************************************************************************/
7066
7067/*
7068 * a couple of forward declarations since we use a recursive call based
7069 * implementation.
7070 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007071static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007072static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007073static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007074static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00007075static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
7076 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00007077
7078/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00007079 * xmlXPathCurrentChar:
7080 * @ctxt: the XPath parser context
7081 * @cur: pointer to the beginning of the char
7082 * @len: pointer to the length of the char read
7083 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007084 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00007085 * bytes in the input buffer.
7086 *
Daniel Veillard60087f32001-10-10 09:45:09 +00007087 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00007088 */
7089
7090static int
7091xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
7092 unsigned char c;
7093 unsigned int val;
7094 const xmlChar *cur;
7095
7096 if (ctxt == NULL)
7097 return(0);
7098 cur = ctxt->cur;
7099
7100 /*
7101 * We are supposed to handle UTF8, check it's valid
7102 * From rfc2044: encoding of the Unicode values on UTF-8:
7103 *
7104 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
7105 * 0000 0000-0000 007F 0xxxxxxx
7106 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
7107 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
7108 *
7109 * Check for the 0x110000 limit too
7110 */
7111 c = *cur;
7112 if (c & 0x80) {
7113 if ((cur[1] & 0xc0) != 0x80)
7114 goto encoding_error;
7115 if ((c & 0xe0) == 0xe0) {
7116
7117 if ((cur[2] & 0xc0) != 0x80)
7118 goto encoding_error;
7119 if ((c & 0xf0) == 0xf0) {
7120 if (((c & 0xf8) != 0xf0) ||
7121 ((cur[3] & 0xc0) != 0x80))
7122 goto encoding_error;
7123 /* 4-byte code */
7124 *len = 4;
7125 val = (cur[0] & 0x7) << 18;
7126 val |= (cur[1] & 0x3f) << 12;
7127 val |= (cur[2] & 0x3f) << 6;
7128 val |= cur[3] & 0x3f;
7129 } else {
7130 /* 3-byte code */
7131 *len = 3;
7132 val = (cur[0] & 0xf) << 12;
7133 val |= (cur[1] & 0x3f) << 6;
7134 val |= cur[2] & 0x3f;
7135 }
7136 } else {
7137 /* 2-byte code */
7138 *len = 2;
7139 val = (cur[0] & 0x1f) << 6;
7140 val |= cur[1] & 0x3f;
7141 }
7142 if (!IS_CHAR(val)) {
7143 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
7144 }
7145 return(val);
7146 } else {
7147 /* 1-byte code */
7148 *len = 1;
7149 return((int) *cur);
7150 }
7151encoding_error:
7152 /*
7153 * If we detect an UTF8 error that probably mean that the
7154 * input encoding didn't get properly advertized in the
7155 * declaration header. Report the error and switch the encoding
7156 * to ISO-Latin-1 (if you don't like this policy, just declare the
7157 * encoding !)
7158 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00007159 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00007160 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007161}
7162
7163/**
Owen Taylor3473f882001-02-23 17:55:21 +00007164 * xmlXPathParseNCName:
7165 * @ctxt: the XPath Parser context
7166 *
7167 * parse an XML namespace non qualified name.
7168 *
7169 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7170 *
7171 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7172 * CombiningChar | Extender
7173 *
7174 * Returns the namespace name or NULL
7175 */
7176
7177xmlChar *
7178xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00007179 const xmlChar *in;
7180 xmlChar *ret;
7181 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007182
Daniel Veillard2156a562001-04-28 12:24:34 +00007183 /*
7184 * Accelerator for simple ASCII names
7185 */
7186 in = ctxt->cur;
7187 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7188 ((*in >= 0x41) && (*in <= 0x5A)) ||
7189 (*in == '_')) {
7190 in++;
7191 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7192 ((*in >= 0x41) && (*in <= 0x5A)) ||
7193 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00007194 (*in == '_') || (*in == '.') ||
7195 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00007196 in++;
7197 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7198 (*in == '[') || (*in == ']') || (*in == ':') ||
7199 (*in == '@') || (*in == '*')) {
7200 count = in - ctxt->cur;
7201 if (count == 0)
7202 return(NULL);
7203 ret = xmlStrndup(ctxt->cur, count);
7204 ctxt->cur = in;
7205 return(ret);
7206 }
7207 }
7208 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00007209}
7210
Daniel Veillard2156a562001-04-28 12:24:34 +00007211
Owen Taylor3473f882001-02-23 17:55:21 +00007212/**
7213 * xmlXPathParseQName:
7214 * @ctxt: the XPath Parser context
7215 * @prefix: a xmlChar **
7216 *
7217 * parse an XML qualified name
7218 *
7219 * [NS 5] QName ::= (Prefix ':')? LocalPart
7220 *
7221 * [NS 6] Prefix ::= NCName
7222 *
7223 * [NS 7] LocalPart ::= NCName
7224 *
7225 * Returns the function returns the local part, and prefix is updated
7226 * to get the Prefix if any.
7227 */
7228
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007229static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007230xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7231 xmlChar *ret = NULL;
7232
7233 *prefix = NULL;
7234 ret = xmlXPathParseNCName(ctxt);
7235 if (CUR == ':') {
7236 *prefix = ret;
7237 NEXT;
7238 ret = xmlXPathParseNCName(ctxt);
7239 }
7240 return(ret);
7241}
7242
7243/**
7244 * xmlXPathParseName:
7245 * @ctxt: the XPath Parser context
7246 *
7247 * parse an XML name
7248 *
7249 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7250 * CombiningChar | Extender
7251 *
7252 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7253 *
7254 * Returns the namespace name or NULL
7255 */
7256
7257xmlChar *
7258xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007259 const xmlChar *in;
7260 xmlChar *ret;
7261 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007262
Daniel Veillard61d80a22001-04-27 17:13:01 +00007263 /*
7264 * Accelerator for simple ASCII names
7265 */
7266 in = ctxt->cur;
7267 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7268 ((*in >= 0x41) && (*in <= 0x5A)) ||
7269 (*in == '_') || (*in == ':')) {
7270 in++;
7271 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7272 ((*in >= 0x41) && (*in <= 0x5A)) ||
7273 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00007274 (*in == '_') || (*in == '-') ||
7275 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00007276 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007277 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007278 count = in - ctxt->cur;
7279 ret = xmlStrndup(ctxt->cur, count);
7280 ctxt->cur = in;
7281 return(ret);
7282 }
7283 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007284 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00007285}
7286
Daniel Veillard61d80a22001-04-27 17:13:01 +00007287static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00007288xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007289 xmlChar buf[XML_MAX_NAMELEN + 5];
7290 int len = 0, l;
7291 int c;
7292
7293 /*
7294 * Handler for more complex cases
7295 */
7296 c = CUR_CHAR(l);
7297 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00007298 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7299 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00007300 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00007301 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007302 return(NULL);
7303 }
7304
7305 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7306 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7307 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007308 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007309 (IS_COMBINING(c)) ||
7310 (IS_EXTENDER(c)))) {
7311 COPY_BUF(l,buf,len,c);
7312 NEXTL(l);
7313 c = CUR_CHAR(l);
7314 if (len >= XML_MAX_NAMELEN) {
7315 /*
7316 * Okay someone managed to make a huge name, so he's ready to pay
7317 * for the processing speed.
7318 */
7319 xmlChar *buffer;
7320 int max = len * 2;
7321
7322 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
7323 if (buffer == NULL) {
7324 XP_ERROR0(XPATH_MEMORY_ERROR);
7325 }
7326 memcpy(buffer, buf, len);
7327 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7328 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007329 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007330 (IS_COMBINING(c)) ||
7331 (IS_EXTENDER(c))) {
7332 if (len + 10 > max) {
7333 max *= 2;
7334 buffer = (xmlChar *) xmlRealloc(buffer,
7335 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007336 if (buffer == NULL) {
7337 XP_ERROR0(XPATH_MEMORY_ERROR);
7338 }
7339 }
7340 COPY_BUF(l,buffer,len,c);
7341 NEXTL(l);
7342 c = CUR_CHAR(l);
7343 }
7344 buffer[len] = 0;
7345 return(buffer);
7346 }
7347 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007348 if (len == 0)
7349 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007350 return(xmlStrndup(buf, len));
7351}
Daniel Veillard3cd72402002-05-13 10:33:30 +00007352
7353#define MAX_FRAC 20
7354
7355static double my_pow10[MAX_FRAC] = {
7356 1.0, 10.0, 100.0, 1000.0, 10000.0,
7357 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7358 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7359 100000000000000.0,
7360 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
7361 1000000000000000000.0, 10000000000000000000.0
7362};
7363
Owen Taylor3473f882001-02-23 17:55:21 +00007364/**
7365 * xmlXPathStringEvalNumber:
7366 * @str: A string to scan
7367 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00007368 * [30a] Float ::= Number ('e' Digits?)?
7369 *
Owen Taylor3473f882001-02-23 17:55:21 +00007370 * [30] Number ::= Digits ('.' Digits?)?
7371 * | '.' Digits
7372 * [31] Digits ::= [0-9]+
7373 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007374 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00007375 * In complement of the Number expression, this function also handles
7376 * negative values : '-' Number.
7377 *
7378 * Returns the double value.
7379 */
7380double
7381xmlXPathStringEvalNumber(const xmlChar *str) {
7382 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00007383 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007384 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007385 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007386 int exponent = 0;
7387 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007388#ifdef __GNUC__
7389 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007390 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007391#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00007392 if (cur == NULL) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00007393 while (IS_BLANK(*cur)) cur++;
7394 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7395 return(xmlXPathNAN);
7396 }
7397 if (*cur == '-') {
7398 isneg = 1;
7399 cur++;
7400 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007401
7402#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007403 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007404 * tmp/temp is a workaround against a gcc compiler bug
7405 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007406 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007407 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007408 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007409 ret = ret * 10;
7410 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00007411 ok = 1;
7412 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00007413 temp = (double) tmp;
7414 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007415 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007416#else
Daniel Veillard7b416132002-03-07 08:36:03 +00007417 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007418 while ((*cur >= '0') && (*cur <= '9')) {
7419 ret = ret * 10 + (*cur - '0');
7420 ok = 1;
7421 cur++;
7422 }
7423#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007424
Owen Taylor3473f882001-02-23 17:55:21 +00007425 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007426 int v, frac = 0;
7427 double fraction = 0;
7428
Owen Taylor3473f882001-02-23 17:55:21 +00007429 cur++;
7430 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7431 return(xmlXPathNAN);
7432 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007433 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
7434 v = (*cur - '0');
7435 fraction = fraction * 10 + v;
7436 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007437 cur++;
7438 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007439 fraction /= my_pow10[frac];
7440 ret = ret + fraction;
7441 while ((*cur >= '0') && (*cur <= '9'))
7442 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007443 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007444 if ((*cur == 'e') || (*cur == 'E')) {
7445 cur++;
7446 if (*cur == '-') {
7447 is_exponent_negative = 1;
7448 cur++;
7449 }
7450 while ((*cur >= '0') && (*cur <= '9')) {
7451 exponent = exponent * 10 + (*cur - '0');
7452 cur++;
7453 }
7454 }
Owen Taylor3473f882001-02-23 17:55:21 +00007455 while (IS_BLANK(*cur)) cur++;
7456 if (*cur != 0) return(xmlXPathNAN);
7457 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007458 if (is_exponent_negative) exponent = -exponent;
7459 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007460 return(ret);
7461}
7462
7463/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007464 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007465 * @ctxt: the XPath Parser context
7466 *
7467 * [30] Number ::= Digits ('.' Digits?)?
7468 * | '.' Digits
7469 * [31] Digits ::= [0-9]+
7470 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007471 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007472 *
7473 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007474static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007475xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7476{
Owen Taylor3473f882001-02-23 17:55:21 +00007477 double ret = 0.0;
7478 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007479 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007480 int exponent = 0;
7481 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007482#ifdef __GNUC__
7483 unsigned long tmp = 0;
7484 double temp;
7485#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007486
7487 CHECK_ERROR;
7488 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7489 XP_ERROR(XPATH_NUMBER_ERROR);
7490 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007491#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007492 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007493 * tmp/temp is a workaround against a gcc compiler bug
7494 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007495 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007496 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007497 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007498 ret = ret * 10;
7499 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007500 ok = 1;
7501 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007502 temp = (double) tmp;
7503 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007504 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007505#else
7506 ret = 0;
7507 while ((CUR >= '0') && (CUR <= '9')) {
7508 ret = ret * 10 + (CUR - '0');
7509 ok = 1;
7510 NEXT;
7511 }
7512#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007513 if (CUR == '.') {
7514 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007515 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7516 XP_ERROR(XPATH_NUMBER_ERROR);
7517 }
7518 while ((CUR >= '0') && (CUR <= '9')) {
7519 mult /= 10;
7520 ret = ret + (CUR - '0') * mult;
7521 NEXT;
7522 }
Owen Taylor3473f882001-02-23 17:55:21 +00007523 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007524 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007525 NEXT;
7526 if (CUR == '-') {
7527 is_exponent_negative = 1;
7528 NEXT;
7529 }
7530 while ((CUR >= '0') && (CUR <= '9')) {
7531 exponent = exponent * 10 + (CUR - '0');
7532 NEXT;
7533 }
7534 if (is_exponent_negative)
7535 exponent = -exponent;
7536 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007537 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007538 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007539 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007540}
7541
7542/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007543 * xmlXPathParseLiteral:
7544 * @ctxt: the XPath Parser context
7545 *
7546 * Parse a Literal
7547 *
7548 * [29] Literal ::= '"' [^"]* '"'
7549 * | "'" [^']* "'"
7550 *
7551 * Returns the value found or NULL in case of error
7552 */
7553static xmlChar *
7554xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7555 const xmlChar *q;
7556 xmlChar *ret = NULL;
7557
7558 if (CUR == '"') {
7559 NEXT;
7560 q = CUR_PTR;
7561 while ((IS_CHAR(CUR)) && (CUR != '"'))
7562 NEXT;
7563 if (!IS_CHAR(CUR)) {
7564 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7565 } else {
7566 ret = xmlStrndup(q, CUR_PTR - q);
7567 NEXT;
7568 }
7569 } else if (CUR == '\'') {
7570 NEXT;
7571 q = CUR_PTR;
7572 while ((IS_CHAR(CUR)) && (CUR != '\''))
7573 NEXT;
7574 if (!IS_CHAR(CUR)) {
7575 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7576 } else {
7577 ret = xmlStrndup(q, CUR_PTR - q);
7578 NEXT;
7579 }
7580 } else {
7581 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7582 }
7583 return(ret);
7584}
7585
7586/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007587 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007588 * @ctxt: the XPath Parser context
7589 *
7590 * Parse a Literal and push it on the stack.
7591 *
7592 * [29] Literal ::= '"' [^"]* '"'
7593 * | "'" [^']* "'"
7594 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007595 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007596 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007597static void
7598xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007599 const xmlChar *q;
7600 xmlChar *ret = NULL;
7601
7602 if (CUR == '"') {
7603 NEXT;
7604 q = CUR_PTR;
7605 while ((IS_CHAR(CUR)) && (CUR != '"'))
7606 NEXT;
7607 if (!IS_CHAR(CUR)) {
7608 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7609 } else {
7610 ret = xmlStrndup(q, CUR_PTR - q);
7611 NEXT;
7612 }
7613 } else if (CUR == '\'') {
7614 NEXT;
7615 q = CUR_PTR;
7616 while ((IS_CHAR(CUR)) && (CUR != '\''))
7617 NEXT;
7618 if (!IS_CHAR(CUR)) {
7619 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7620 } else {
7621 ret = xmlStrndup(q, CUR_PTR - q);
7622 NEXT;
7623 }
7624 } else {
7625 XP_ERROR(XPATH_START_LITERAL_ERROR);
7626 }
7627 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007628 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7629 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007630 xmlFree(ret);
7631}
7632
7633/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007634 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007635 * @ctxt: the XPath Parser context
7636 *
7637 * Parse a VariableReference, evaluate it and push it on the stack.
7638 *
7639 * The variable bindings consist of a mapping from variable names
7640 * to variable values. The value of a variable is an object, which
7641 * of any of the types that are possible for the value of an expression,
7642 * and may also be of additional types not specified here.
7643 *
7644 * Early evaluation is possible since:
7645 * The variable bindings [...] used to evaluate a subexpression are
7646 * always the same as those used to evaluate the containing expression.
7647 *
7648 * [36] VariableReference ::= '$' QName
7649 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007650static void
7651xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007652 xmlChar *name;
7653 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007654
7655 SKIP_BLANKS;
7656 if (CUR != '$') {
7657 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7658 }
7659 NEXT;
7660 name = xmlXPathParseQName(ctxt, &prefix);
7661 if (name == NULL) {
7662 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7663 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007664 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007665 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7666 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007667 SKIP_BLANKS;
7668}
7669
7670/**
7671 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +00007672 * @name: a name string
7673 *
7674 * Is the name given a NodeType one.
7675 *
7676 * [38] NodeType ::= 'comment'
7677 * | 'text'
7678 * | 'processing-instruction'
7679 * | 'node'
7680 *
7681 * Returns 1 if true 0 otherwise
7682 */
7683int
7684xmlXPathIsNodeType(const xmlChar *name) {
7685 if (name == NULL)
7686 return(0);
7687
Daniel Veillard1971ee22002-01-31 20:29:19 +00007688 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007689 return(1);
7690 if (xmlStrEqual(name, BAD_CAST "text"))
7691 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007692 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007693 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007694 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007695 return(1);
7696 return(0);
7697}
7698
7699/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007700 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007701 * @ctxt: the XPath Parser context
7702 *
7703 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7704 * [17] Argument ::= Expr
7705 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007706 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007707 * pushed on the stack
7708 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007709static void
7710xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007711 xmlChar *name;
7712 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007713 int nbargs = 0;
7714
7715 name = xmlXPathParseQName(ctxt, &prefix);
7716 if (name == NULL) {
7717 XP_ERROR(XPATH_EXPR_ERROR);
7718 }
7719 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007720#ifdef DEBUG_EXPR
7721 if (prefix == NULL)
7722 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7723 name);
7724 else
7725 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7726 prefix, name);
7727#endif
7728
Owen Taylor3473f882001-02-23 17:55:21 +00007729 if (CUR != '(') {
7730 XP_ERROR(XPATH_EXPR_ERROR);
7731 }
7732 NEXT;
7733 SKIP_BLANKS;
7734
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007735 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +00007736 if (CUR != ')') {
7737 while (CUR != 0) {
7738 int op1 = ctxt->comp->last;
7739 ctxt->comp->last = -1;
7740 xmlXPathCompileExpr(ctxt);
7741 CHECK_ERROR;
7742 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
7743 nbargs++;
7744 if (CUR == ')') break;
7745 if (CUR != ',') {
7746 XP_ERROR(XPATH_EXPR_ERROR);
7747 }
7748 NEXT;
7749 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007750 }
Owen Taylor3473f882001-02-23 17:55:21 +00007751 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007752 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7753 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007754 NEXT;
7755 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007756}
7757
7758/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007759 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007760 * @ctxt: the XPath Parser context
7761 *
7762 * [15] PrimaryExpr ::= VariableReference
7763 * | '(' Expr ')'
7764 * | Literal
7765 * | Number
7766 * | FunctionCall
7767 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007768 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007769 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007770static void
7771xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007772 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007773 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007774 else if (CUR == '(') {
7775 NEXT;
7776 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007777 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007778 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00007779 if (CUR != ')') {
7780 XP_ERROR(XPATH_EXPR_ERROR);
7781 }
7782 NEXT;
7783 SKIP_BLANKS;
Daniel Veillard01917aa2002-04-10 11:30:41 +00007784 } else if (IS_DIGIT(CUR) || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007785 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007786 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007787 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007788 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007789 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007790 }
7791 SKIP_BLANKS;
7792}
7793
7794/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007795 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007796 * @ctxt: the XPath Parser context
7797 *
7798 * [20] FilterExpr ::= PrimaryExpr
7799 * | FilterExpr Predicate
7800 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007801 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007802 * Square brackets are used to filter expressions in the same way that
7803 * they are used in location paths. It is an error if the expression to
7804 * be filtered does not evaluate to a node-set. The context node list
7805 * used for evaluating the expression in square brackets is the node-set
7806 * to be filtered listed in document order.
7807 */
7808
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007809static void
7810xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
7811 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007812 CHECK_ERROR;
7813 SKIP_BLANKS;
7814
7815 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007816 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00007817 SKIP_BLANKS;
7818 }
7819
7820
7821}
7822
7823/**
7824 * xmlXPathScanName:
7825 * @ctxt: the XPath Parser context
7826 *
7827 * Trickery: parse an XML name but without consuming the input flow
7828 * Needed to avoid insanity in the parser state.
7829 *
7830 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7831 * CombiningChar | Extender
7832 *
7833 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7834 *
7835 * [6] Names ::= Name (S Name)*
7836 *
7837 * Returns the Name parsed or NULL
7838 */
7839
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007840static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007841xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7842 xmlChar buf[XML_MAX_NAMELEN];
7843 int len = 0;
7844
7845 SKIP_BLANKS;
7846 if (!IS_LETTER(CUR) && (CUR != '_') &&
7847 (CUR != ':')) {
7848 return(NULL);
7849 }
7850
7851 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7852 (NXT(len) == '.') || (NXT(len) == '-') ||
7853 (NXT(len) == '_') || (NXT(len) == ':') ||
7854 (IS_COMBINING(NXT(len))) ||
7855 (IS_EXTENDER(NXT(len)))) {
7856 buf[len] = NXT(len);
7857 len++;
7858 if (len >= XML_MAX_NAMELEN) {
7859 xmlGenericError(xmlGenericErrorContext,
7860 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
7861 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7862 (NXT(len) == '.') || (NXT(len) == '-') ||
7863 (NXT(len) == '_') || (NXT(len) == ':') ||
7864 (IS_COMBINING(NXT(len))) ||
7865 (IS_EXTENDER(NXT(len))))
7866 len++;
7867 break;
7868 }
7869 }
7870 return(xmlStrndup(buf, len));
7871}
7872
7873/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007874 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007875 * @ctxt: the XPath Parser context
7876 *
7877 * [19] PathExpr ::= LocationPath
7878 * | FilterExpr
7879 * | FilterExpr '/' RelativeLocationPath
7880 * | FilterExpr '//' RelativeLocationPath
7881 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007882 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007883 * The / operator and // operators combine an arbitrary expression
7884 * and a relative location path. It is an error if the expression
7885 * does not evaluate to a node-set.
7886 * The / operator does composition in the same way as when / is
7887 * used in a location path. As in location paths, // is short for
7888 * /descendant-or-self::node()/.
7889 */
7890
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007891static void
7892xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007893 int lc = 1; /* Should we branch to LocationPath ? */
7894 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7895
7896 SKIP_BLANKS;
7897 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
Daniel Veillard01917aa2002-04-10 11:30:41 +00007898 (CUR == '\'') || (CUR == '"') || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00007899 lc = 0;
7900 } else if (CUR == '*') {
7901 /* relative or absolute location path */
7902 lc = 1;
7903 } else if (CUR == '/') {
7904 /* relative or absolute location path */
7905 lc = 1;
7906 } else if (CUR == '@') {
7907 /* relative abbreviated attribute location path */
7908 lc = 1;
7909 } else if (CUR == '.') {
7910 /* relative abbreviated attribute location path */
7911 lc = 1;
7912 } else {
7913 /*
7914 * Problem is finding if we have a name here whether it's:
7915 * - a nodetype
7916 * - a function call in which case it's followed by '('
7917 * - an axis in which case it's followed by ':'
7918 * - a element name
7919 * We do an a priori analysis here rather than having to
7920 * maintain parsed token content through the recursive function
7921 * calls. This looks uglier but makes the code quite easier to
7922 * read/write/debug.
7923 */
7924 SKIP_BLANKS;
7925 name = xmlXPathScanName(ctxt);
7926 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7927#ifdef DEBUG_STEP
7928 xmlGenericError(xmlGenericErrorContext,
7929 "PathExpr: Axis\n");
7930#endif
7931 lc = 1;
7932 xmlFree(name);
7933 } else if (name != NULL) {
7934 int len =xmlStrlen(name);
7935 int blank = 0;
7936
7937
7938 while (NXT(len) != 0) {
7939 if (NXT(len) == '/') {
7940 /* element name */
7941#ifdef DEBUG_STEP
7942 xmlGenericError(xmlGenericErrorContext,
7943 "PathExpr: AbbrRelLocation\n");
7944#endif
7945 lc = 1;
7946 break;
7947 } else if (IS_BLANK(NXT(len))) {
7948 /* skip to next */
7949 blank = 1;
7950 } else if (NXT(len) == ':') {
7951#ifdef DEBUG_STEP
7952 xmlGenericError(xmlGenericErrorContext,
7953 "PathExpr: AbbrRelLocation\n");
7954#endif
7955 lc = 1;
7956 break;
7957 } else if ((NXT(len) == '(')) {
7958 /* Note Type or Function */
7959 if (xmlXPathIsNodeType(name)) {
7960#ifdef DEBUG_STEP
7961 xmlGenericError(xmlGenericErrorContext,
7962 "PathExpr: Type search\n");
7963#endif
7964 lc = 1;
7965 } else {
7966#ifdef DEBUG_STEP
7967 xmlGenericError(xmlGenericErrorContext,
7968 "PathExpr: function call\n");
7969#endif
7970 lc = 0;
7971 }
7972 break;
7973 } else if ((NXT(len) == '[')) {
7974 /* element name */
7975#ifdef DEBUG_STEP
7976 xmlGenericError(xmlGenericErrorContext,
7977 "PathExpr: AbbrRelLocation\n");
7978#endif
7979 lc = 1;
7980 break;
7981 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
7982 (NXT(len) == '=')) {
7983 lc = 1;
7984 break;
7985 } else {
7986 lc = 1;
7987 break;
7988 }
7989 len++;
7990 }
7991 if (NXT(len) == 0) {
7992#ifdef DEBUG_STEP
7993 xmlGenericError(xmlGenericErrorContext,
7994 "PathExpr: AbbrRelLocation\n");
7995#endif
7996 /* element name */
7997 lc = 1;
7998 }
7999 xmlFree(name);
8000 } else {
8001 /* make sure all cases are covered explicitely */
8002 XP_ERROR(XPATH_EXPR_ERROR);
8003 }
8004 }
8005
8006 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008007 if (CUR == '/') {
8008 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8009 } else {
8010 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008011 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008012 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008013 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008014 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008015 CHECK_ERROR;
8016 if ((CUR == '/') && (NXT(1) == '/')) {
8017 SKIP(2);
8018 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008019
8020 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8021 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8022 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
8023
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008024 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008025 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008026 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008027 }
8028 }
8029 SKIP_BLANKS;
8030}
8031
8032/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008033 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008034 * @ctxt: the XPath Parser context
8035 *
8036 * [18] UnionExpr ::= PathExpr
8037 * | UnionExpr '|' PathExpr
8038 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008039 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008040 */
8041
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008042static void
8043xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8044 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008045 CHECK_ERROR;
8046 SKIP_BLANKS;
8047 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008048 int op1 = ctxt->comp->last;
8049 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008050
8051 NEXT;
8052 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008053 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008054
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008055 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8056
Owen Taylor3473f882001-02-23 17:55:21 +00008057 SKIP_BLANKS;
8058 }
Owen Taylor3473f882001-02-23 17:55:21 +00008059}
8060
8061/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008062 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008063 * @ctxt: the XPath Parser context
8064 *
8065 * [27] UnaryExpr ::= UnionExpr
8066 * | '-' UnaryExpr
8067 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008068 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008069 */
8070
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008071static void
8072xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008073 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008074 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008075
8076 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00008077 while (CUR == '-') {
8078 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008079 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008080 NEXT;
8081 SKIP_BLANKS;
8082 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008083
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008084 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008085 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008086 if (found) {
8087 if (minus)
8088 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8089 else
8090 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008091 }
8092}
8093
8094/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008095 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008096 * @ctxt: the XPath Parser context
8097 *
8098 * [26] MultiplicativeExpr ::= UnaryExpr
8099 * | MultiplicativeExpr MultiplyOperator UnaryExpr
8100 * | MultiplicativeExpr 'div' UnaryExpr
8101 * | MultiplicativeExpr 'mod' UnaryExpr
8102 * [34] MultiplyOperator ::= '*'
8103 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008104 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008105 */
8106
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008107static void
8108xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8109 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008110 CHECK_ERROR;
8111 SKIP_BLANKS;
8112 while ((CUR == '*') ||
8113 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8114 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8115 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008116 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008117
8118 if (CUR == '*') {
8119 op = 0;
8120 NEXT;
8121 } else if (CUR == 'd') {
8122 op = 1;
8123 SKIP(3);
8124 } else if (CUR == 'm') {
8125 op = 2;
8126 SKIP(3);
8127 }
8128 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008129 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008130 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008131 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008132 SKIP_BLANKS;
8133 }
8134}
8135
8136/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008137 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008138 * @ctxt: the XPath Parser context
8139 *
8140 * [25] AdditiveExpr ::= MultiplicativeExpr
8141 * | AdditiveExpr '+' MultiplicativeExpr
8142 * | AdditiveExpr '-' MultiplicativeExpr
8143 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008144 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008145 */
8146
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008147static void
8148xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008149
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008150 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008151 CHECK_ERROR;
8152 SKIP_BLANKS;
8153 while ((CUR == '+') || (CUR == '-')) {
8154 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008155 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008156
8157 if (CUR == '+') plus = 1;
8158 else plus = 0;
8159 NEXT;
8160 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008161 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008162 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008163 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008164 SKIP_BLANKS;
8165 }
8166}
8167
8168/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008169 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008170 * @ctxt: the XPath Parser context
8171 *
8172 * [24] RelationalExpr ::= AdditiveExpr
8173 * | RelationalExpr '<' AdditiveExpr
8174 * | RelationalExpr '>' AdditiveExpr
8175 * | RelationalExpr '<=' AdditiveExpr
8176 * | RelationalExpr '>=' AdditiveExpr
8177 *
8178 * A <= B > C is allowed ? Answer from James, yes with
8179 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8180 * which is basically what got implemented.
8181 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008182 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00008183 * on the stack
8184 */
8185
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008186static void
8187xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8188 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008189 CHECK_ERROR;
8190 SKIP_BLANKS;
8191 while ((CUR == '<') ||
8192 (CUR == '>') ||
8193 ((CUR == '<') && (NXT(1) == '=')) ||
8194 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008195 int inf, strict;
8196 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008197
8198 if (CUR == '<') inf = 1;
8199 else inf = 0;
8200 if (NXT(1) == '=') strict = 0;
8201 else strict = 1;
8202 NEXT;
8203 if (!strict) NEXT;
8204 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008205 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008206 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008207 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00008208 SKIP_BLANKS;
8209 }
8210}
8211
8212/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008213 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008214 * @ctxt: the XPath Parser context
8215 *
8216 * [23] EqualityExpr ::= RelationalExpr
8217 * | EqualityExpr '=' RelationalExpr
8218 * | EqualityExpr '!=' RelationalExpr
8219 *
8220 * A != B != C is allowed ? Answer from James, yes with
8221 * (RelationalExpr = RelationalExpr) = RelationalExpr
8222 * (RelationalExpr != RelationalExpr) != RelationalExpr
8223 * which is basically what got implemented.
8224 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008225 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008226 *
8227 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008228static void
8229xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8230 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008231 CHECK_ERROR;
8232 SKIP_BLANKS;
8233 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008234 int eq;
8235 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008236
8237 if (CUR == '=') eq = 1;
8238 else eq = 0;
8239 NEXT;
8240 if (!eq) NEXT;
8241 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008242 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008243 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008244 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008245 SKIP_BLANKS;
8246 }
8247}
8248
8249/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008250 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008251 * @ctxt: the XPath Parser context
8252 *
8253 * [22] AndExpr ::= EqualityExpr
8254 * | AndExpr 'and' EqualityExpr
8255 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008256 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008257 *
8258 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008259static void
8260xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8261 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008262 CHECK_ERROR;
8263 SKIP_BLANKS;
8264 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008265 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008266 SKIP(3);
8267 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008268 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008269 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008270 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008271 SKIP_BLANKS;
8272 }
8273}
8274
8275/**
Daniel Veillard591b4be2003-02-09 23:33:36 +00008276 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008277 * @ctxt: the XPath Parser context
8278 *
8279 * [14] Expr ::= OrExpr
8280 * [21] OrExpr ::= AndExpr
8281 * | OrExpr 'or' AndExpr
8282 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008283 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00008284 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008285static void
8286xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8287 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008288 CHECK_ERROR;
8289 SKIP_BLANKS;
8290 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008291 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008292 SKIP(2);
8293 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008294 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008295 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008296 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8297 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00008298 SKIP_BLANKS;
8299 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008300 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8301 /* more ops could be optimized too */
8302 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8303 }
Owen Taylor3473f882001-02-23 17:55:21 +00008304}
8305
8306/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008307 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00008308 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008309 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00008310 *
8311 * [8] Predicate ::= '[' PredicateExpr ']'
8312 * [9] PredicateExpr ::= Expr
8313 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008314 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008315 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008316static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008317xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008318 int op1 = ctxt->comp->last;
8319
8320 SKIP_BLANKS;
8321 if (CUR != '[') {
8322 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8323 }
8324 NEXT;
8325 SKIP_BLANKS;
8326
8327 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008328 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008329 CHECK_ERROR;
8330
8331 if (CUR != ']') {
8332 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8333 }
8334
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008335 if (filter)
8336 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8337 else
8338 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008339
8340 NEXT;
8341 SKIP_BLANKS;
8342}
8343
8344/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008345 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00008346 * @ctxt: the XPath Parser context
8347 * @test: pointer to a xmlXPathTestVal
8348 * @type: pointer to a xmlXPathTypeVal
8349 * @prefix: placeholder for a possible name prefix
8350 *
8351 * [7] NodeTest ::= NameTest
8352 * | NodeType '(' ')'
8353 * | 'processing-instruction' '(' Literal ')'
8354 *
8355 * [37] NameTest ::= '*'
8356 * | NCName ':' '*'
8357 * | QName
8358 * [38] NodeType ::= 'comment'
8359 * | 'text'
8360 * | 'processing-instruction'
8361 * | 'node'
8362 *
8363 * Returns the name found and update @test, @type and @prefix appropriately
8364 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008365static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008366xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8367 xmlXPathTypeVal *type, const xmlChar **prefix,
8368 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008369 int blanks;
8370
8371 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8372 STRANGE;
8373 return(NULL);
8374 }
8375 *type = 0;
8376 *test = 0;
8377 *prefix = NULL;
8378 SKIP_BLANKS;
8379
8380 if ((name == NULL) && (CUR == '*')) {
8381 /*
8382 * All elements
8383 */
8384 NEXT;
8385 *test = NODE_TEST_ALL;
8386 return(NULL);
8387 }
8388
8389 if (name == NULL)
8390 name = xmlXPathParseNCName(ctxt);
8391 if (name == NULL) {
8392 XP_ERROR0(XPATH_EXPR_ERROR);
8393 }
8394
8395 blanks = IS_BLANK(CUR);
8396 SKIP_BLANKS;
8397 if (CUR == '(') {
8398 NEXT;
8399 /*
8400 * NodeType or PI search
8401 */
8402 if (xmlStrEqual(name, BAD_CAST "comment"))
8403 *type = NODE_TYPE_COMMENT;
8404 else if (xmlStrEqual(name, BAD_CAST "node"))
8405 *type = NODE_TYPE_NODE;
8406 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8407 *type = NODE_TYPE_PI;
8408 else if (xmlStrEqual(name, BAD_CAST "text"))
8409 *type = NODE_TYPE_TEXT;
8410 else {
8411 if (name != NULL)
8412 xmlFree(name);
8413 XP_ERROR0(XPATH_EXPR_ERROR);
8414 }
8415
8416 *test = NODE_TEST_TYPE;
8417
8418 SKIP_BLANKS;
8419 if (*type == NODE_TYPE_PI) {
8420 /*
8421 * Specific case: search a PI by name.
8422 */
Owen Taylor3473f882001-02-23 17:55:21 +00008423 if (name != NULL)
8424 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008425 name = NULL;
8426 if (CUR != ')') {
8427 name = xmlXPathParseLiteral(ctxt);
8428 CHECK_ERROR 0;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00008429 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00008430 SKIP_BLANKS;
8431 }
Owen Taylor3473f882001-02-23 17:55:21 +00008432 }
8433 if (CUR != ')') {
8434 if (name != NULL)
8435 xmlFree(name);
8436 XP_ERROR0(XPATH_UNCLOSED_ERROR);
8437 }
8438 NEXT;
8439 return(name);
8440 }
8441 *test = NODE_TEST_NAME;
8442 if ((!blanks) && (CUR == ':')) {
8443 NEXT;
8444
8445 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008446 * Since currently the parser context don't have a
8447 * namespace list associated:
8448 * The namespace name for this prefix can be computed
8449 * only at evaluation time. The compilation is done
8450 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008451 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008452#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008453 *prefix = xmlXPathNsLookup(ctxt->context, name);
8454 if (name != NULL)
8455 xmlFree(name);
8456 if (*prefix == NULL) {
8457 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8458 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008459#else
8460 *prefix = name;
8461#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008462
8463 if (CUR == '*') {
8464 /*
8465 * All elements
8466 */
8467 NEXT;
8468 *test = NODE_TEST_ALL;
8469 return(NULL);
8470 }
8471
8472 name = xmlXPathParseNCName(ctxt);
8473 if (name == NULL) {
8474 XP_ERROR0(XPATH_EXPR_ERROR);
8475 }
8476 }
8477 return(name);
8478}
8479
8480/**
8481 * xmlXPathIsAxisName:
8482 * @name: a preparsed name token
8483 *
8484 * [6] AxisName ::= 'ancestor'
8485 * | 'ancestor-or-self'
8486 * | 'attribute'
8487 * | 'child'
8488 * | 'descendant'
8489 * | 'descendant-or-self'
8490 * | 'following'
8491 * | 'following-sibling'
8492 * | 'namespace'
8493 * | 'parent'
8494 * | 'preceding'
8495 * | 'preceding-sibling'
8496 * | 'self'
8497 *
8498 * Returns the axis or 0
8499 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008500static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008501xmlXPathIsAxisName(const xmlChar *name) {
8502 xmlXPathAxisVal ret = 0;
8503 switch (name[0]) {
8504 case 'a':
8505 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8506 ret = AXIS_ANCESTOR;
8507 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8508 ret = AXIS_ANCESTOR_OR_SELF;
8509 if (xmlStrEqual(name, BAD_CAST "attribute"))
8510 ret = AXIS_ATTRIBUTE;
8511 break;
8512 case 'c':
8513 if (xmlStrEqual(name, BAD_CAST "child"))
8514 ret = AXIS_CHILD;
8515 break;
8516 case 'd':
8517 if (xmlStrEqual(name, BAD_CAST "descendant"))
8518 ret = AXIS_DESCENDANT;
8519 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8520 ret = AXIS_DESCENDANT_OR_SELF;
8521 break;
8522 case 'f':
8523 if (xmlStrEqual(name, BAD_CAST "following"))
8524 ret = AXIS_FOLLOWING;
8525 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8526 ret = AXIS_FOLLOWING_SIBLING;
8527 break;
8528 case 'n':
8529 if (xmlStrEqual(name, BAD_CAST "namespace"))
8530 ret = AXIS_NAMESPACE;
8531 break;
8532 case 'p':
8533 if (xmlStrEqual(name, BAD_CAST "parent"))
8534 ret = AXIS_PARENT;
8535 if (xmlStrEqual(name, BAD_CAST "preceding"))
8536 ret = AXIS_PRECEDING;
8537 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8538 ret = AXIS_PRECEDING_SIBLING;
8539 break;
8540 case 's':
8541 if (xmlStrEqual(name, BAD_CAST "self"))
8542 ret = AXIS_SELF;
8543 break;
8544 }
8545 return(ret);
8546}
8547
8548/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008549 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008550 * @ctxt: the XPath Parser context
8551 *
8552 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8553 * | AbbreviatedStep
8554 *
8555 * [12] AbbreviatedStep ::= '.' | '..'
8556 *
8557 * [5] AxisSpecifier ::= AxisName '::'
8558 * | AbbreviatedAxisSpecifier
8559 *
8560 * [13] AbbreviatedAxisSpecifier ::= '@'?
8561 *
8562 * Modified for XPtr range support as:
8563 *
8564 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8565 * | AbbreviatedStep
8566 * | 'range-to' '(' Expr ')' Predicate*
8567 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008568 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008569 * A location step of . is short for self::node(). This is
8570 * particularly useful in conjunction with //. For example, the
8571 * location path .//para is short for
8572 * self::node()/descendant-or-self::node()/child::para
8573 * and so will select all para descendant elements of the context
8574 * node.
8575 * Similarly, a location step of .. is short for parent::node().
8576 * For example, ../title is short for parent::node()/child::title
8577 * and so will select the title children of the parent of the context
8578 * node.
8579 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008580static void
8581xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008582#ifdef LIBXML_XPTR_ENABLED
8583 int rangeto = 0;
8584 int op2 = -1;
8585#endif
8586
Owen Taylor3473f882001-02-23 17:55:21 +00008587 SKIP_BLANKS;
8588 if ((CUR == '.') && (NXT(1) == '.')) {
8589 SKIP(2);
8590 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008591 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8592 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008593 } else if (CUR == '.') {
8594 NEXT;
8595 SKIP_BLANKS;
8596 } else {
8597 xmlChar *name = NULL;
8598 const xmlChar *prefix = NULL;
8599 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008600 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008601 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008602 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008603
8604 /*
8605 * The modification needed for XPointer change to the production
8606 */
8607#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008608 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008609 name = xmlXPathParseNCName(ctxt);
8610 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008611 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008612 xmlFree(name);
8613 SKIP_BLANKS;
8614 if (CUR != '(') {
8615 XP_ERROR(XPATH_EXPR_ERROR);
8616 }
8617 NEXT;
8618 SKIP_BLANKS;
8619
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008620 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008621 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008622 CHECK_ERROR;
8623
8624 SKIP_BLANKS;
8625 if (CUR != ')') {
8626 XP_ERROR(XPATH_EXPR_ERROR);
8627 }
8628 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008629 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008630 goto eval_predicates;
8631 }
8632 }
8633#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008634 if (CUR == '*') {
8635 axis = AXIS_CHILD;
8636 } else {
8637 if (name == NULL)
8638 name = xmlXPathParseNCName(ctxt);
8639 if (name != NULL) {
8640 axis = xmlXPathIsAxisName(name);
8641 if (axis != 0) {
8642 SKIP_BLANKS;
8643 if ((CUR == ':') && (NXT(1) == ':')) {
8644 SKIP(2);
8645 xmlFree(name);
8646 name = NULL;
8647 } else {
8648 /* an element name can conflict with an axis one :-\ */
8649 axis = AXIS_CHILD;
8650 }
Owen Taylor3473f882001-02-23 17:55:21 +00008651 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008652 axis = AXIS_CHILD;
8653 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008654 } else if (CUR == '@') {
8655 NEXT;
8656 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008657 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008658 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008659 }
Owen Taylor3473f882001-02-23 17:55:21 +00008660 }
8661
8662 CHECK_ERROR;
8663
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008664 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008665 if (test == 0)
8666 return;
8667
8668#ifdef DEBUG_STEP
8669 xmlGenericError(xmlGenericErrorContext,
8670 "Basis : computing new set\n");
8671#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008672
Owen Taylor3473f882001-02-23 17:55:21 +00008673#ifdef DEBUG_STEP
8674 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008675 if (ctxt->value == NULL)
8676 xmlGenericError(xmlGenericErrorContext, "no value\n");
8677 else if (ctxt->value->nodesetval == NULL)
8678 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8679 else
8680 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008681#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008682
8683eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008684 op1 = ctxt->comp->last;
8685 ctxt->comp->last = -1;
8686
Owen Taylor3473f882001-02-23 17:55:21 +00008687 SKIP_BLANKS;
8688 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008689 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008690 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008691
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008692#ifdef LIBXML_XPTR_ENABLED
8693 if (rangeto) {
8694 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8695 } else
8696#endif
8697 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8698 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008699
Owen Taylor3473f882001-02-23 17:55:21 +00008700 }
8701#ifdef DEBUG_STEP
8702 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008703 if (ctxt->value == NULL)
8704 xmlGenericError(xmlGenericErrorContext, "no value\n");
8705 else if (ctxt->value->nodesetval == NULL)
8706 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8707 else
8708 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8709 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008710#endif
8711}
8712
8713/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008714 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008715 * @ctxt: the XPath Parser context
8716 *
8717 * [3] RelativeLocationPath ::= Step
8718 * | RelativeLocationPath '/' Step
8719 * | AbbreviatedRelativeLocationPath
8720 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8721 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008722 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008723 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008724static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008725xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008726(xmlXPathParserContextPtr ctxt) {
8727 SKIP_BLANKS;
8728 if ((CUR == '/') && (NXT(1) == '/')) {
8729 SKIP(2);
8730 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008731 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8732 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008733 } else if (CUR == '/') {
8734 NEXT;
8735 SKIP_BLANKS;
8736 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008737 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008738 SKIP_BLANKS;
8739 while (CUR == '/') {
8740 if ((CUR == '/') && (NXT(1) == '/')) {
8741 SKIP(2);
8742 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008743 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008744 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008745 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008746 } else if (CUR == '/') {
8747 NEXT;
8748 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008749 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008750 }
8751 SKIP_BLANKS;
8752 }
8753}
8754
8755/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008756 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008757 * @ctxt: the XPath Parser context
8758 *
8759 * [1] LocationPath ::= RelativeLocationPath
8760 * | AbsoluteLocationPath
8761 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8762 * | AbbreviatedAbsoluteLocationPath
8763 * [10] AbbreviatedAbsoluteLocationPath ::=
8764 * '//' RelativeLocationPath
8765 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008766 * Compile a location path
8767 *
Owen Taylor3473f882001-02-23 17:55:21 +00008768 * // is short for /descendant-or-self::node()/. For example,
8769 * //para is short for /descendant-or-self::node()/child::para and
8770 * so will select any para element in the document (even a para element
8771 * that is a document element will be selected by //para since the
8772 * document element node is a child of the root node); div//para is
8773 * short for div/descendant-or-self::node()/child::para and so will
8774 * select all para descendants of div children.
8775 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008776static void
8777xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008778 SKIP_BLANKS;
8779 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008780 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008781 } else {
8782 while (CUR == '/') {
8783 if ((CUR == '/') && (NXT(1) == '/')) {
8784 SKIP(2);
8785 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008786 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8787 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008788 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008789 } else if (CUR == '/') {
8790 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008791 SKIP_BLANKS;
8792 if ((CUR != 0 ) &&
8793 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
8794 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008795 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008796 }
8797 }
8798 }
8799}
8800
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008801/************************************************************************
8802 * *
8803 * XPath precompiled expression evaluation *
8804 * *
8805 ************************************************************************/
8806
Daniel Veillardf06307e2001-07-03 10:35:50 +00008807static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008808xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8809
8810/**
8811 * xmlXPathNodeCollectAndTest:
8812 * @ctxt: the XPath Parser context
8813 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008814 * @first: pointer to the first element in document order
8815 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008816 *
8817 * This is the function implementing a step: based on the current list
8818 * of nodes, it builds up a new list, looking at all nodes under that
8819 * axis and selecting them it also do the predicate filtering
8820 *
8821 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00008822 *
8823 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008824 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008825static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008826xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008827 xmlXPathStepOpPtr op,
8828 xmlNodePtr * first, xmlNodePtr * last)
8829{
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008830 xmlXPathAxisVal axis = op->value;
8831 xmlXPathTestVal test = op->value2;
8832 xmlXPathTypeVal type = op->value3;
8833 const xmlChar *prefix = op->value4;
8834 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008835 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008836
8837#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008838 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008839#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008840 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008841 xmlNodeSetPtr ret, list;
8842 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008843 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00008844 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008845 xmlNodePtr cur = NULL;
8846 xmlXPathObjectPtr obj;
8847 xmlNodeSetPtr nodelist;
8848 xmlNodePtr tmp;
8849
Daniel Veillardf06307e2001-07-03 10:35:50 +00008850 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008851 obj = valuePop(ctxt);
8852 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00008853 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008854 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008855 URI = xmlXPathNsLookup(ctxt->context, prefix);
8856 if (URI == NULL)
8857 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008858 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008859#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008860 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008861#endif
8862 switch (axis) {
8863 case AXIS_ANCESTOR:
8864#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008865 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008866#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008867 first = NULL;
8868 next = xmlXPathNextAncestor;
8869 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008870 case AXIS_ANCESTOR_OR_SELF:
8871#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008872 xmlGenericError(xmlGenericErrorContext,
8873 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008874#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008875 first = NULL;
8876 next = xmlXPathNextAncestorOrSelf;
8877 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008878 case AXIS_ATTRIBUTE:
8879#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008880 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008881#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008882 first = NULL;
8883 last = NULL;
8884 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00008885 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008886 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008887 case AXIS_CHILD:
8888#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008889 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008890#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008891 last = NULL;
8892 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00008893 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008894 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008895 case AXIS_DESCENDANT:
8896#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008897 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008898#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008899 last = NULL;
8900 next = xmlXPathNextDescendant;
8901 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008902 case AXIS_DESCENDANT_OR_SELF:
8903#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008904 xmlGenericError(xmlGenericErrorContext,
8905 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008906#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008907 last = NULL;
8908 next = xmlXPathNextDescendantOrSelf;
8909 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008910 case AXIS_FOLLOWING:
8911#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008912 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008913#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008914 last = NULL;
8915 next = xmlXPathNextFollowing;
8916 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008917 case AXIS_FOLLOWING_SIBLING:
8918#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008919 xmlGenericError(xmlGenericErrorContext,
8920 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008921#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008922 last = NULL;
8923 next = xmlXPathNextFollowingSibling;
8924 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008925 case AXIS_NAMESPACE:
8926#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008927 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008928#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008929 first = NULL;
8930 last = NULL;
8931 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00008932 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008933 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008934 case AXIS_PARENT:
8935#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008936 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008937#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008938 first = NULL;
8939 next = xmlXPathNextParent;
8940 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008941 case AXIS_PRECEDING:
8942#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008943 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008944#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008945 first = NULL;
8946 next = xmlXPathNextPrecedingInternal;
8947 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008948 case AXIS_PRECEDING_SIBLING:
8949#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008950 xmlGenericError(xmlGenericErrorContext,
8951 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008952#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008953 first = NULL;
8954 next = xmlXPathNextPrecedingSibling;
8955 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008956 case AXIS_SELF:
8957#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008958 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008959#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008960 first = NULL;
8961 last = NULL;
8962 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00008963 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008964 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008965 }
8966 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008967 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008968
8969 nodelist = obj->nodesetval;
8970 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008971 xmlXPathFreeObject(obj);
8972 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8973 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008974 }
8975 addNode = xmlXPathNodeSetAddUnique;
8976 ret = NULL;
8977#ifdef DEBUG_STEP
8978 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008979 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008980 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008981 case NODE_TEST_NONE:
8982 xmlGenericError(xmlGenericErrorContext,
8983 " searching for none !!!\n");
8984 break;
8985 case NODE_TEST_TYPE:
8986 xmlGenericError(xmlGenericErrorContext,
8987 " searching for type %d\n", type);
8988 break;
8989 case NODE_TEST_PI:
8990 xmlGenericError(xmlGenericErrorContext,
8991 " searching for PI !!!\n");
8992 break;
8993 case NODE_TEST_ALL:
8994 xmlGenericError(xmlGenericErrorContext,
8995 " searching for *\n");
8996 break;
8997 case NODE_TEST_NS:
8998 xmlGenericError(xmlGenericErrorContext,
8999 " searching for namespace %s\n",
9000 prefix);
9001 break;
9002 case NODE_TEST_NAME:
9003 xmlGenericError(xmlGenericErrorContext,
9004 " searching for name %s\n", name);
9005 if (prefix != NULL)
9006 xmlGenericError(xmlGenericErrorContext,
9007 " with namespace %s\n", prefix);
9008 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009009 }
9010 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9011#endif
9012 /*
9013 * 2.3 Node Tests
9014 * - For the attribute axis, the principal node type is attribute.
9015 * - For the namespace axis, the principal node type is namespace.
9016 * - For other axes, the principal node type is element.
9017 *
9018 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009019 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009020 * select all element children of the context node
9021 */
9022 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009023 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009024 ctxt->context->node = nodelist->nodeTab[i];
9025
Daniel Veillardf06307e2001-07-03 10:35:50 +00009026 cur = NULL;
9027 list = xmlXPathNodeSetCreate(NULL);
9028 do {
9029 cur = next(ctxt, cur);
9030 if (cur == NULL)
9031 break;
9032 if ((first != NULL) && (*first == cur))
9033 break;
9034 if (((t % 256) == 0) &&
9035 (first != NULL) && (*first != NULL) &&
9036 (xmlXPathCmpNodes(*first, cur) >= 0))
9037 break;
9038 if ((last != NULL) && (*last == cur))
9039 break;
9040 if (((t % 256) == 0) &&
9041 (last != NULL) && (*last != NULL) &&
9042 (xmlXPathCmpNodes(cur, *last) >= 0))
9043 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009044 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009045#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009046 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
9047#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009048 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009049 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009050 ctxt->context->node = tmp;
9051 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009052 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009053 if ((cur->type == type) ||
9054 ((type == NODE_TYPE_NODE) &&
9055 ((cur->type == XML_DOCUMENT_NODE) ||
9056 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9057 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00009058 (cur->type == XML_NAMESPACE_DECL) ||
9059 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00009060 (cur->type == XML_PI_NODE) ||
9061 (cur->type == XML_COMMENT_NODE) ||
9062 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00009063 (cur->type == XML_TEXT_NODE))) ||
9064 ((type == NODE_TYPE_TEXT) &&
9065 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009066#ifdef DEBUG_STEP
9067 n++;
9068#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009069 addNode(list, cur);
9070 }
9071 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009072 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009073 if (cur->type == XML_PI_NODE) {
9074 if ((name != NULL) &&
9075 (!xmlStrEqual(name, cur->name)))
9076 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009077#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009078 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009079#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009080 addNode(list, cur);
9081 }
9082 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009083 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009084 if (axis == AXIS_ATTRIBUTE) {
9085 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009086#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009087 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009088#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009089 addNode(list, cur);
9090 }
9091 } else if (axis == AXIS_NAMESPACE) {
9092 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009093#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009094 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009095#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009096 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9097 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009098 }
9099 } else {
9100 if (cur->type == XML_ELEMENT_NODE) {
9101 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009102#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009103 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009104#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009105 addNode(list, cur);
9106 } else if ((cur->ns != NULL) &&
9107 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009108#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009109 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009110#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009111 addNode(list, cur);
9112 }
9113 }
9114 }
9115 break;
9116 case NODE_TEST_NS:{
9117 TODO;
9118 break;
9119 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009120 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009121 switch (cur->type) {
9122 case XML_ELEMENT_NODE:
9123 if (xmlStrEqual(name, cur->name)) {
9124 if (prefix == NULL) {
9125 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009126#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009127 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009128#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009129 addNode(list, cur);
9130 }
9131 } else {
9132 if ((cur->ns != NULL) &&
9133 (xmlStrEqual(URI,
9134 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009135#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009136 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009137#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009138 addNode(list, cur);
9139 }
9140 }
9141 }
9142 break;
9143 case XML_ATTRIBUTE_NODE:{
9144 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009145
Daniel Veillardf06307e2001-07-03 10:35:50 +00009146 if (xmlStrEqual(name, attr->name)) {
9147 if (prefix == NULL) {
9148 if ((attr->ns == NULL) ||
9149 (attr->ns->prefix == NULL)) {
9150#ifdef DEBUG_STEP
9151 n++;
9152#endif
9153 addNode(list,
9154 (xmlNodePtr) attr);
9155 }
9156 } else {
9157 if ((attr->ns != NULL) &&
9158 (xmlStrEqual(URI,
9159 attr->ns->
9160 href))) {
9161#ifdef DEBUG_STEP
9162 n++;
9163#endif
9164 addNode(list,
9165 (xmlNodePtr) attr);
9166 }
9167 }
9168 }
9169 break;
9170 }
9171 case XML_NAMESPACE_DECL:
9172 if (cur->type == XML_NAMESPACE_DECL) {
9173 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009174
Daniel Veillardf06307e2001-07-03 10:35:50 +00009175 if ((ns->prefix != NULL) && (name != NULL)
9176 && (xmlStrEqual(ns->prefix, name))) {
9177#ifdef DEBUG_STEP
9178 n++;
9179#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009180 xmlXPathNodeSetAddNs(list,
9181 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009182 }
9183 }
9184 break;
9185 default:
9186 break;
9187 }
9188 break;
9189 break;
9190 }
9191 } while (cur != NULL);
9192
9193 /*
9194 * If there is some predicate filtering do it now
9195 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009196 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009197 xmlXPathObjectPtr obj2;
9198
9199 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9200 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9201 CHECK_TYPE0(XPATH_NODESET);
9202 obj2 = valuePop(ctxt);
9203 list = obj2->nodesetval;
9204 obj2->nodesetval = NULL;
9205 xmlXPathFreeObject(obj2);
9206 }
9207 if (ret == NULL) {
9208 ret = list;
9209 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009210 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009211 xmlXPathFreeNodeSet(list);
9212 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009213 }
9214 ctxt->context->node = tmp;
9215#ifdef DEBUG_STEP
9216 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009217 "\nExamined %d nodes, found %d nodes at that step\n",
9218 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009219#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009220 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009221 if ((obj->boolval) && (obj->user != NULL)) {
9222 ctxt->value->boolval = 1;
9223 ctxt->value->user = obj->user;
9224 obj->user = NULL;
9225 obj->boolval = 0;
9226 }
9227 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009228 return(t);
9229}
9230
9231/**
9232 * xmlXPathNodeCollectAndTestNth:
9233 * @ctxt: the XPath Parser context
9234 * @op: the XPath precompiled step operation
9235 * @indx: the index to collect
9236 * @first: pointer to the first element in document order
9237 * @last: pointer to the last element in document order
9238 *
9239 * This is the function implementing a step: based on the current list
9240 * of nodes, it builds up a new list, looking at all nodes under that
9241 * axis and selecting them it also do the predicate filtering
9242 *
9243 * Pushes the new NodeSet resulting from the search.
9244 * Returns the number of node traversed
9245 */
9246static int
9247xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9248 xmlXPathStepOpPtr op, int indx,
9249 xmlNodePtr * first, xmlNodePtr * last)
9250{
9251 xmlXPathAxisVal axis = op->value;
9252 xmlXPathTestVal test = op->value2;
9253 xmlXPathTypeVal type = op->value3;
9254 const xmlChar *prefix = op->value4;
9255 const xmlChar *name = op->value5;
9256 const xmlChar *URI = NULL;
9257 int n = 0, t = 0;
9258
9259 int i;
9260 xmlNodeSetPtr list;
9261 xmlXPathTraversalFunction next = NULL;
9262 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9263 xmlNodePtr cur = NULL;
9264 xmlXPathObjectPtr obj;
9265 xmlNodeSetPtr nodelist;
9266 xmlNodePtr tmp;
9267
9268 CHECK_TYPE0(XPATH_NODESET);
9269 obj = valuePop(ctxt);
9270 addNode = xmlXPathNodeSetAdd;
9271 if (prefix != NULL) {
9272 URI = xmlXPathNsLookup(ctxt->context, prefix);
9273 if (URI == NULL)
9274 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9275 }
9276#ifdef DEBUG_STEP_NTH
9277 xmlGenericError(xmlGenericErrorContext, "new step : ");
9278 if (first != NULL) {
9279 if (*first != NULL)
9280 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9281 (*first)->name);
9282 else
9283 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9284 }
9285 if (last != NULL) {
9286 if (*last != NULL)
9287 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9288 (*last)->name);
9289 else
9290 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9291 }
9292#endif
9293 switch (axis) {
9294 case AXIS_ANCESTOR:
9295#ifdef DEBUG_STEP_NTH
9296 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9297#endif
9298 first = NULL;
9299 next = xmlXPathNextAncestor;
9300 break;
9301 case AXIS_ANCESTOR_OR_SELF:
9302#ifdef DEBUG_STEP_NTH
9303 xmlGenericError(xmlGenericErrorContext,
9304 "axis 'ancestors-or-self' ");
9305#endif
9306 first = NULL;
9307 next = xmlXPathNextAncestorOrSelf;
9308 break;
9309 case AXIS_ATTRIBUTE:
9310#ifdef DEBUG_STEP_NTH
9311 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9312#endif
9313 first = NULL;
9314 last = NULL;
9315 next = xmlXPathNextAttribute;
9316 break;
9317 case AXIS_CHILD:
9318#ifdef DEBUG_STEP_NTH
9319 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9320#endif
9321 last = NULL;
9322 next = xmlXPathNextChild;
9323 break;
9324 case AXIS_DESCENDANT:
9325#ifdef DEBUG_STEP_NTH
9326 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9327#endif
9328 last = NULL;
9329 next = xmlXPathNextDescendant;
9330 break;
9331 case AXIS_DESCENDANT_OR_SELF:
9332#ifdef DEBUG_STEP_NTH
9333 xmlGenericError(xmlGenericErrorContext,
9334 "axis 'descendant-or-self' ");
9335#endif
9336 last = NULL;
9337 next = xmlXPathNextDescendantOrSelf;
9338 break;
9339 case AXIS_FOLLOWING:
9340#ifdef DEBUG_STEP_NTH
9341 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9342#endif
9343 last = NULL;
9344 next = xmlXPathNextFollowing;
9345 break;
9346 case AXIS_FOLLOWING_SIBLING:
9347#ifdef DEBUG_STEP_NTH
9348 xmlGenericError(xmlGenericErrorContext,
9349 "axis 'following-siblings' ");
9350#endif
9351 last = NULL;
9352 next = xmlXPathNextFollowingSibling;
9353 break;
9354 case AXIS_NAMESPACE:
9355#ifdef DEBUG_STEP_NTH
9356 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9357#endif
9358 last = NULL;
9359 first = NULL;
9360 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9361 break;
9362 case AXIS_PARENT:
9363#ifdef DEBUG_STEP_NTH
9364 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9365#endif
9366 first = NULL;
9367 next = xmlXPathNextParent;
9368 break;
9369 case AXIS_PRECEDING:
9370#ifdef DEBUG_STEP_NTH
9371 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9372#endif
9373 first = NULL;
9374 next = xmlXPathNextPrecedingInternal;
9375 break;
9376 case AXIS_PRECEDING_SIBLING:
9377#ifdef DEBUG_STEP_NTH
9378 xmlGenericError(xmlGenericErrorContext,
9379 "axis 'preceding-sibling' ");
9380#endif
9381 first = NULL;
9382 next = xmlXPathNextPrecedingSibling;
9383 break;
9384 case AXIS_SELF:
9385#ifdef DEBUG_STEP_NTH
9386 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9387#endif
9388 first = NULL;
9389 last = NULL;
9390 next = xmlXPathNextSelf;
9391 break;
9392 }
9393 if (next == NULL)
9394 return(0);
9395
9396 nodelist = obj->nodesetval;
9397 if (nodelist == NULL) {
9398 xmlXPathFreeObject(obj);
9399 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9400 return(0);
9401 }
9402 addNode = xmlXPathNodeSetAddUnique;
9403#ifdef DEBUG_STEP_NTH
9404 xmlGenericError(xmlGenericErrorContext,
9405 " context contains %d nodes\n", nodelist->nodeNr);
9406 switch (test) {
9407 case NODE_TEST_NONE:
9408 xmlGenericError(xmlGenericErrorContext,
9409 " searching for none !!!\n");
9410 break;
9411 case NODE_TEST_TYPE:
9412 xmlGenericError(xmlGenericErrorContext,
9413 " searching for type %d\n", type);
9414 break;
9415 case NODE_TEST_PI:
9416 xmlGenericError(xmlGenericErrorContext,
9417 " searching for PI !!!\n");
9418 break;
9419 case NODE_TEST_ALL:
9420 xmlGenericError(xmlGenericErrorContext,
9421 " searching for *\n");
9422 break;
9423 case NODE_TEST_NS:
9424 xmlGenericError(xmlGenericErrorContext,
9425 " searching for namespace %s\n",
9426 prefix);
9427 break;
9428 case NODE_TEST_NAME:
9429 xmlGenericError(xmlGenericErrorContext,
9430 " searching for name %s\n", name);
9431 if (prefix != NULL)
9432 xmlGenericError(xmlGenericErrorContext,
9433 " with namespace %s\n", prefix);
9434 break;
9435 }
9436 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9437#endif
9438 /*
9439 * 2.3 Node Tests
9440 * - For the attribute axis, the principal node type is attribute.
9441 * - For the namespace axis, the principal node type is namespace.
9442 * - For other axes, the principal node type is element.
9443 *
9444 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009445 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009446 * select all element children of the context node
9447 */
9448 tmp = ctxt->context->node;
9449 list = xmlXPathNodeSetCreate(NULL);
9450 for (i = 0; i < nodelist->nodeNr; i++) {
9451 ctxt->context->node = nodelist->nodeTab[i];
9452
9453 cur = NULL;
9454 n = 0;
9455 do {
9456 cur = next(ctxt, cur);
9457 if (cur == NULL)
9458 break;
9459 if ((first != NULL) && (*first == cur))
9460 break;
9461 if (((t % 256) == 0) &&
9462 (first != NULL) && (*first != NULL) &&
9463 (xmlXPathCmpNodes(*first, cur) >= 0))
9464 break;
9465 if ((last != NULL) && (*last == cur))
9466 break;
9467 if (((t % 256) == 0) &&
9468 (last != NULL) && (*last != NULL) &&
9469 (xmlXPathCmpNodes(cur, *last) >= 0))
9470 break;
9471 t++;
9472 switch (test) {
9473 case NODE_TEST_NONE:
9474 ctxt->context->node = tmp;
9475 STRANGE return(0);
9476 case NODE_TEST_TYPE:
9477 if ((cur->type == type) ||
9478 ((type == NODE_TYPE_NODE) &&
9479 ((cur->type == XML_DOCUMENT_NODE) ||
9480 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9481 (cur->type == XML_ELEMENT_NODE) ||
9482 (cur->type == XML_PI_NODE) ||
9483 (cur->type == XML_COMMENT_NODE) ||
9484 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +00009485 (cur->type == XML_TEXT_NODE))) ||
9486 ((type == NODE_TYPE_TEXT) &&
9487 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009488 n++;
9489 if (n == indx)
9490 addNode(list, cur);
9491 }
9492 break;
9493 case NODE_TEST_PI:
9494 if (cur->type == XML_PI_NODE) {
9495 if ((name != NULL) &&
9496 (!xmlStrEqual(name, cur->name)))
9497 break;
9498 n++;
9499 if (n == indx)
9500 addNode(list, cur);
9501 }
9502 break;
9503 case NODE_TEST_ALL:
9504 if (axis == AXIS_ATTRIBUTE) {
9505 if (cur->type == XML_ATTRIBUTE_NODE) {
9506 n++;
9507 if (n == indx)
9508 addNode(list, cur);
9509 }
9510 } else if (axis == AXIS_NAMESPACE) {
9511 if (cur->type == XML_NAMESPACE_DECL) {
9512 n++;
9513 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009514 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9515 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009516 }
9517 } else {
9518 if (cur->type == XML_ELEMENT_NODE) {
9519 if (prefix == NULL) {
9520 n++;
9521 if (n == indx)
9522 addNode(list, cur);
9523 } else if ((cur->ns != NULL) &&
9524 (xmlStrEqual(URI, cur->ns->href))) {
9525 n++;
9526 if (n == indx)
9527 addNode(list, cur);
9528 }
9529 }
9530 }
9531 break;
9532 case NODE_TEST_NS:{
9533 TODO;
9534 break;
9535 }
9536 case NODE_TEST_NAME:
9537 switch (cur->type) {
9538 case XML_ELEMENT_NODE:
9539 if (xmlStrEqual(name, cur->name)) {
9540 if (prefix == NULL) {
9541 if (cur->ns == NULL) {
9542 n++;
9543 if (n == indx)
9544 addNode(list, cur);
9545 }
9546 } else {
9547 if ((cur->ns != NULL) &&
9548 (xmlStrEqual(URI,
9549 cur->ns->href))) {
9550 n++;
9551 if (n == indx)
9552 addNode(list, cur);
9553 }
9554 }
9555 }
9556 break;
9557 case XML_ATTRIBUTE_NODE:{
9558 xmlAttrPtr attr = (xmlAttrPtr) cur;
9559
9560 if (xmlStrEqual(name, attr->name)) {
9561 if (prefix == NULL) {
9562 if ((attr->ns == NULL) ||
9563 (attr->ns->prefix == NULL)) {
9564 n++;
9565 if (n == indx)
9566 addNode(list, cur);
9567 }
9568 } else {
9569 if ((attr->ns != NULL) &&
9570 (xmlStrEqual(URI,
9571 attr->ns->
9572 href))) {
9573 n++;
9574 if (n == indx)
9575 addNode(list, cur);
9576 }
9577 }
9578 }
9579 break;
9580 }
9581 case XML_NAMESPACE_DECL:
9582 if (cur->type == XML_NAMESPACE_DECL) {
9583 xmlNsPtr ns = (xmlNsPtr) cur;
9584
9585 if ((ns->prefix != NULL) && (name != NULL)
9586 && (xmlStrEqual(ns->prefix, name))) {
9587 n++;
9588 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009589 xmlXPathNodeSetAddNs(list,
9590 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009591 }
9592 }
9593 break;
9594 default:
9595 break;
9596 }
9597 break;
9598 break;
9599 }
9600 } while (n < indx);
9601 }
9602 ctxt->context->node = tmp;
9603#ifdef DEBUG_STEP_NTH
9604 xmlGenericError(xmlGenericErrorContext,
9605 "\nExamined %d nodes, found %d nodes at that step\n",
9606 t, list->nodeNr);
9607#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009608 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009609 if ((obj->boolval) && (obj->user != NULL)) {
9610 ctxt->value->boolval = 1;
9611 ctxt->value->user = obj->user;
9612 obj->user = NULL;
9613 obj->boolval = 0;
9614 }
9615 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009616 return(t);
9617}
9618
9619/**
9620 * xmlXPathCompOpEvalFirst:
9621 * @ctxt: the XPath parser context with the compiled expression
9622 * @op: an XPath compiled operation
9623 * @first: the first elem found so far
9624 *
9625 * Evaluate the Precompiled XPath operation searching only the first
9626 * element in document order
9627 *
9628 * Returns the number of examined objects.
9629 */
9630static int
9631xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9632 xmlXPathStepOpPtr op, xmlNodePtr * first)
9633{
9634 int total = 0, cur;
9635 xmlXPathCompExprPtr comp;
9636 xmlXPathObjectPtr arg1, arg2;
9637
Daniel Veillard556c6682001-10-06 09:59:51 +00009638 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009639 comp = ctxt->comp;
9640 switch (op->op) {
9641 case XPATH_OP_END:
9642 return (0);
9643 case XPATH_OP_UNION:
9644 total =
9645 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9646 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009647 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009648 if ((ctxt->value != NULL)
9649 && (ctxt->value->type == XPATH_NODESET)
9650 && (ctxt->value->nodesetval != NULL)
9651 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9652 /*
9653 * limit tree traversing to first node in the result
9654 */
9655 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9656 *first = ctxt->value->nodesetval->nodeTab[0];
9657 }
9658 cur =
9659 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9660 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009661 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009662 CHECK_TYPE0(XPATH_NODESET);
9663 arg2 = valuePop(ctxt);
9664
9665 CHECK_TYPE0(XPATH_NODESET);
9666 arg1 = valuePop(ctxt);
9667
9668 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9669 arg2->nodesetval);
9670 valuePush(ctxt, arg1);
9671 xmlXPathFreeObject(arg2);
9672 /* optimizer */
9673 if (total > cur)
9674 xmlXPathCompSwap(op);
9675 return (total + cur);
9676 case XPATH_OP_ROOT:
9677 xmlXPathRoot(ctxt);
9678 return (0);
9679 case XPATH_OP_NODE:
9680 if (op->ch1 != -1)
9681 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009682 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009683 if (op->ch2 != -1)
9684 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009685 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009686 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9687 return (total);
9688 case XPATH_OP_RESET:
9689 if (op->ch1 != -1)
9690 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009691 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009692 if (op->ch2 != -1)
9693 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009694 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009695 ctxt->context->node = NULL;
9696 return (total);
9697 case XPATH_OP_COLLECT:{
9698 if (op->ch1 == -1)
9699 return (total);
9700
9701 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009702 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009703
9704 /*
9705 * Optimization for [n] selection where n is a number
9706 */
9707 if ((op->ch2 != -1) &&
9708 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9709 (comp->steps[op->ch2].ch1 == -1) &&
9710 (comp->steps[op->ch2].ch2 != -1) &&
9711 (comp->steps[comp->steps[op->ch2].ch2].op ==
9712 XPATH_OP_VALUE)) {
9713 xmlXPathObjectPtr val;
9714
9715 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9716 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9717 int indx = (int) val->floatval;
9718
9719 if (val->floatval == (float) indx) {
9720 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9721 first, NULL);
9722 return (total);
9723 }
9724 }
9725 }
9726 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9727 return (total);
9728 }
9729 case XPATH_OP_VALUE:
9730 valuePush(ctxt,
9731 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9732 return (0);
9733 case XPATH_OP_SORT:
9734 if (op->ch1 != -1)
9735 total +=
9736 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9737 first);
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 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9743 return (total);
9744 default:
9745 return (xmlXPathCompOpEval(ctxt, op));
9746 }
9747}
9748
9749/**
9750 * xmlXPathCompOpEvalLast:
9751 * @ctxt: the XPath parser context with the compiled expression
9752 * @op: an XPath compiled operation
9753 * @last: the last elem found so far
9754 *
9755 * Evaluate the Precompiled XPath operation searching only the last
9756 * element in document order
9757 *
9758 * Returns the number of node traversed
9759 */
9760static int
9761xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9762 xmlNodePtr * last)
9763{
9764 int total = 0, cur;
9765 xmlXPathCompExprPtr comp;
9766 xmlXPathObjectPtr arg1, arg2;
9767
Daniel Veillard556c6682001-10-06 09:59:51 +00009768 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009769 comp = ctxt->comp;
9770 switch (op->op) {
9771 case XPATH_OP_END:
9772 return (0);
9773 case XPATH_OP_UNION:
9774 total =
9775 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009776 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009777 if ((ctxt->value != NULL)
9778 && (ctxt->value->type == XPATH_NODESET)
9779 && (ctxt->value->nodesetval != NULL)
9780 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9781 /*
9782 * limit tree traversing to first node in the result
9783 */
9784 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9785 *last =
9786 ctxt->value->nodesetval->nodeTab[ctxt->value->
9787 nodesetval->nodeNr -
9788 1];
9789 }
9790 cur =
9791 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009792 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009793 if ((ctxt->value != NULL)
9794 && (ctxt->value->type == XPATH_NODESET)
9795 && (ctxt->value->nodesetval != NULL)
9796 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9797 }
9798 CHECK_TYPE0(XPATH_NODESET);
9799 arg2 = valuePop(ctxt);
9800
9801 CHECK_TYPE0(XPATH_NODESET);
9802 arg1 = valuePop(ctxt);
9803
9804 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9805 arg2->nodesetval);
9806 valuePush(ctxt, arg1);
9807 xmlXPathFreeObject(arg2);
9808 /* optimizer */
9809 if (total > cur)
9810 xmlXPathCompSwap(op);
9811 return (total + cur);
9812 case XPATH_OP_ROOT:
9813 xmlXPathRoot(ctxt);
9814 return (0);
9815 case XPATH_OP_NODE:
9816 if (op->ch1 != -1)
9817 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009818 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009819 if (op->ch2 != -1)
9820 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009821 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009822 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9823 return (total);
9824 case XPATH_OP_RESET:
9825 if (op->ch1 != -1)
9826 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009827 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009828 if (op->ch2 != -1)
9829 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009830 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009831 ctxt->context->node = NULL;
9832 return (total);
9833 case XPATH_OP_COLLECT:{
9834 if (op->ch1 == -1)
9835 return (0);
9836
9837 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009838 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009839
9840 /*
9841 * Optimization for [n] selection where n is a number
9842 */
9843 if ((op->ch2 != -1) &&
9844 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9845 (comp->steps[op->ch2].ch1 == -1) &&
9846 (comp->steps[op->ch2].ch2 != -1) &&
9847 (comp->steps[comp->steps[op->ch2].ch2].op ==
9848 XPATH_OP_VALUE)) {
9849 xmlXPathObjectPtr val;
9850
9851 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9852 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9853 int indx = (int) val->floatval;
9854
9855 if (val->floatval == (float) indx) {
9856 total +=
9857 xmlXPathNodeCollectAndTestNth(ctxt, op,
9858 indx, NULL,
9859 last);
9860 return (total);
9861 }
9862 }
9863 }
9864 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9865 return (total);
9866 }
9867 case XPATH_OP_VALUE:
9868 valuePush(ctxt,
9869 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9870 return (0);
9871 case XPATH_OP_SORT:
9872 if (op->ch1 != -1)
9873 total +=
9874 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9875 last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009876 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009877 if ((ctxt->value != NULL)
9878 && (ctxt->value->type == XPATH_NODESET)
9879 && (ctxt->value->nodesetval != NULL))
9880 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9881 return (total);
9882 default:
9883 return (xmlXPathCompOpEval(ctxt, op));
9884 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009885}
9886
Owen Taylor3473f882001-02-23 17:55:21 +00009887/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009888 * xmlXPathCompOpEval:
9889 * @ctxt: the XPath parser context with the compiled expression
9890 * @op: an XPath compiled operation
9891 *
9892 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009893 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009894 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009895static int
9896xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9897{
9898 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009899 int equal, ret;
9900 xmlXPathCompExprPtr comp;
9901 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009902 xmlNodePtr bak;
9903 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +00009904 int pp;
William M. Brack692092b2002-06-28 15:01:24 +00009905 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009906
Daniel Veillard556c6682001-10-06 09:59:51 +00009907 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009908 comp = ctxt->comp;
9909 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009910 case XPATH_OP_END:
9911 return (0);
9912 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009913 bakd = ctxt->context->doc;
9914 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009915 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009916 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009917 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009918 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009919 xmlXPathBooleanFunction(ctxt, 1);
9920 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9921 return (total);
9922 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009923 ctxt->context->doc = bakd;
9924 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009925 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009926 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009927 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009928 if (ctxt->error) {
9929 xmlXPathFreeObject(arg2);
9930 return(0);
9931 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009932 xmlXPathBooleanFunction(ctxt, 1);
9933 arg1 = valuePop(ctxt);
9934 arg1->boolval &= arg2->boolval;
9935 valuePush(ctxt, arg1);
9936 xmlXPathFreeObject(arg2);
9937 return (total);
9938 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009939 bakd = ctxt->context->doc;
9940 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009941 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009942 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009943 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009944 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009945 xmlXPathBooleanFunction(ctxt, 1);
9946 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9947 return (total);
9948 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009949 ctxt->context->doc = bakd;
9950 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009951 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009952 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009953 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009954 if (ctxt->error) {
9955 xmlXPathFreeObject(arg2);
9956 return(0);
9957 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009958 xmlXPathBooleanFunction(ctxt, 1);
9959 arg1 = valuePop(ctxt);
9960 arg1->boolval |= arg2->boolval;
9961 valuePush(ctxt, arg1);
9962 xmlXPathFreeObject(arg2);
9963 return (total);
9964 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009965 bakd = ctxt->context->doc;
9966 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009967 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009968 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009969 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009970 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009971 ctxt->context->doc = bakd;
9972 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009973 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009974 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009975 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009976 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +00009977 if (op->value)
9978 equal = xmlXPathEqualValues(ctxt);
9979 else
9980 equal = xmlXPathNotEqualValues(ctxt);
9981 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +00009982 return (total);
9983 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009984 bakd = ctxt->context->doc;
9985 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009986 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009987 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009988 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009989 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009990 ctxt->context->doc = bakd;
9991 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009992 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009993 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009994 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009995 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009996 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
9997 valuePush(ctxt, xmlXPathNewBoolean(ret));
9998 return (total);
9999 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010000 bakd = ctxt->context->doc;
10001 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010002 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010003 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010004 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010005 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010006 if (op->ch2 != -1) {
10007 ctxt->context->doc = bakd;
10008 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010009 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010010 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010011 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010012 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010013 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010014 if (op->value == 0)
10015 xmlXPathSubValues(ctxt);
10016 else if (op->value == 1)
10017 xmlXPathAddValues(ctxt);
10018 else if (op->value == 2)
10019 xmlXPathValueFlipSign(ctxt);
10020 else if (op->value == 3) {
10021 CAST_TO_NUMBER;
10022 CHECK_TYPE0(XPATH_NUMBER);
10023 }
10024 return (total);
10025 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010026 bakd = ctxt->context->doc;
10027 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010028 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010029 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010030 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010031 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010032 ctxt->context->doc = bakd;
10033 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010034 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010035 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010036 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010037 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010038 if (op->value == 0)
10039 xmlXPathMultValues(ctxt);
10040 else if (op->value == 1)
10041 xmlXPathDivValues(ctxt);
10042 else if (op->value == 2)
10043 xmlXPathModValues(ctxt);
10044 return (total);
10045 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010046 bakd = ctxt->context->doc;
10047 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010048 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010049 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010050 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010051 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010052 ctxt->context->doc = bakd;
10053 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010054 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010055 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010056 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010057 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010058 CHECK_TYPE0(XPATH_NODESET);
10059 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010060
Daniel Veillardf06307e2001-07-03 10:35:50 +000010061 CHECK_TYPE0(XPATH_NODESET);
10062 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010063
Daniel Veillardf06307e2001-07-03 10:35:50 +000010064 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10065 arg2->nodesetval);
10066 valuePush(ctxt, arg1);
10067 xmlXPathFreeObject(arg2);
10068 return (total);
10069 case XPATH_OP_ROOT:
10070 xmlXPathRoot(ctxt);
10071 return (total);
10072 case XPATH_OP_NODE:
10073 if (op->ch1 != -1)
10074 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010075 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010076 if (op->ch2 != -1)
10077 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010078 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010079 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10080 return (total);
10081 case XPATH_OP_RESET:
10082 if (op->ch1 != -1)
10083 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010084 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010085 if (op->ch2 != -1)
10086 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010087 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010088 ctxt->context->node = NULL;
10089 return (total);
10090 case XPATH_OP_COLLECT:{
10091 if (op->ch1 == -1)
10092 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010093
Daniel Veillardf06307e2001-07-03 10:35:50 +000010094 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010095 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010096
Daniel Veillardf06307e2001-07-03 10:35:50 +000010097 /*
10098 * Optimization for [n] selection where n is a number
10099 */
10100 if ((op->ch2 != -1) &&
10101 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10102 (comp->steps[op->ch2].ch1 == -1) &&
10103 (comp->steps[op->ch2].ch2 != -1) &&
10104 (comp->steps[comp->steps[op->ch2].ch2].op ==
10105 XPATH_OP_VALUE)) {
10106 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +000010107
Daniel Veillardf06307e2001-07-03 10:35:50 +000010108 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10109 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10110 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010111
Daniel Veillardf06307e2001-07-03 10:35:50 +000010112 if (val->floatval == (float) indx) {
10113 total +=
10114 xmlXPathNodeCollectAndTestNth(ctxt, op,
10115 indx, NULL,
10116 NULL);
10117 return (total);
10118 }
10119 }
10120 }
10121 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
10122 return (total);
10123 }
10124 case XPATH_OP_VALUE:
10125 valuePush(ctxt,
10126 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10127 return (total);
10128 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000010129 xmlXPathObjectPtr val;
10130
Daniel Veillardf06307e2001-07-03 10:35:50 +000010131 if (op->ch1 != -1)
10132 total +=
10133 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010134 if (op->value5 == NULL) {
10135 val = xmlXPathVariableLookup(ctxt->context, op->value4);
10136 if (val == NULL) {
10137 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10138 return(0);
10139 }
10140 valuePush(ctxt, val);
10141 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010142 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010143
Daniel Veillardf06307e2001-07-03 10:35:50 +000010144 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10145 if (URI == NULL) {
10146 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010147 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010148 op->value4, op->value5);
10149 return (total);
10150 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010151 val = xmlXPathVariableLookupNS(ctxt->context,
10152 op->value4, URI);
10153 if (val == NULL) {
10154 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10155 return(0);
10156 }
10157 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010158 }
10159 return (total);
10160 }
10161 case XPATH_OP_FUNCTION:{
10162 xmlXPathFunction func;
10163 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000010164 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010165
10166 if (op->ch1 != -1)
10167 total +=
10168 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010169 if (ctxt->valueNr < op->value) {
10170 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010171 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010172 ctxt->error = XPATH_INVALID_OPERAND;
10173 return (total);
10174 }
10175 for (i = 0; i < op->value; i++)
10176 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10177 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010178 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010179 ctxt->error = XPATH_INVALID_OPERAND;
10180 return (total);
10181 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010182 if (op->cache != NULL)
10183 func = (xmlXPathFunction) op->cache;
10184 else {
10185 const xmlChar *URI = NULL;
10186
10187 if (op->value5 == NULL)
10188 func =
10189 xmlXPathFunctionLookup(ctxt->context,
10190 op->value4);
10191 else {
10192 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10193 if (URI == NULL) {
10194 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010195 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010196 op->value4, op->value5);
10197 return (total);
10198 }
10199 func = xmlXPathFunctionLookupNS(ctxt->context,
10200 op->value4, URI);
10201 }
10202 if (func == NULL) {
10203 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010204 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010205 op->value4);
10206 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010207 }
10208 op->cache = (void *) func;
10209 op->cacheURI = (void *) URI;
10210 }
10211 oldFunc = ctxt->context->function;
10212 oldFuncURI = ctxt->context->functionURI;
10213 ctxt->context->function = op->value4;
10214 ctxt->context->functionURI = op->cacheURI;
10215 func(ctxt, op->value);
10216 ctxt->context->function = oldFunc;
10217 ctxt->context->functionURI = oldFuncURI;
10218 return (total);
10219 }
10220 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000010221 bakd = ctxt->context->doc;
10222 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010223 if (op->ch1 != -1)
10224 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010225 ctxt->context->doc = bakd;
10226 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010227 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010228 if (op->ch2 != -1)
10229 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010230 ctxt->context->doc = bakd;
10231 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010232 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010233 return (total);
10234 case XPATH_OP_PREDICATE:
10235 case XPATH_OP_FILTER:{
10236 xmlXPathObjectPtr res;
10237 xmlXPathObjectPtr obj, tmp;
10238 xmlNodeSetPtr newset = NULL;
10239 xmlNodeSetPtr oldset;
10240 xmlNodePtr oldnode;
10241 int i;
10242
10243 /*
10244 * Optimization for ()[1] selection i.e. the first elem
10245 */
10246 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10247 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10248 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10249 xmlXPathObjectPtr val;
10250
10251 val = comp->steps[op->ch2].value4;
10252 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10253 (val->floatval == 1.0)) {
10254 xmlNodePtr first = NULL;
10255
10256 total +=
10257 xmlXPathCompOpEvalFirst(ctxt,
10258 &comp->steps[op->ch1],
10259 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010260 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010261 /*
10262 * The nodeset should be in document order,
10263 * Keep only the first value
10264 */
10265 if ((ctxt->value != NULL) &&
10266 (ctxt->value->type == XPATH_NODESET) &&
10267 (ctxt->value->nodesetval != NULL) &&
10268 (ctxt->value->nodesetval->nodeNr > 1))
10269 ctxt->value->nodesetval->nodeNr = 1;
10270 return (total);
10271 }
10272 }
10273 /*
10274 * Optimization for ()[last()] selection i.e. the last elem
10275 */
10276 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10277 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10278 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10279 int f = comp->steps[op->ch2].ch1;
10280
10281 if ((f != -1) &&
10282 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10283 (comp->steps[f].value5 == NULL) &&
10284 (comp->steps[f].value == 0) &&
10285 (comp->steps[f].value4 != NULL) &&
10286 (xmlStrEqual
10287 (comp->steps[f].value4, BAD_CAST "last"))) {
10288 xmlNodePtr last = NULL;
10289
10290 total +=
10291 xmlXPathCompOpEvalLast(ctxt,
10292 &comp->steps[op->ch1],
10293 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010294 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010295 /*
10296 * The nodeset should be in document order,
10297 * Keep only the last value
10298 */
10299 if ((ctxt->value != NULL) &&
10300 (ctxt->value->type == XPATH_NODESET) &&
10301 (ctxt->value->nodesetval != NULL) &&
10302 (ctxt->value->nodesetval->nodeTab != NULL) &&
10303 (ctxt->value->nodesetval->nodeNr > 1)) {
10304 ctxt->value->nodesetval->nodeTab[0] =
10305 ctxt->value->nodesetval->nodeTab[ctxt->
10306 value->
10307 nodesetval->
10308 nodeNr -
10309 1];
10310 ctxt->value->nodesetval->nodeNr = 1;
10311 }
10312 return (total);
10313 }
10314 }
10315
10316 if (op->ch1 != -1)
10317 total +=
10318 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010319 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010320 if (op->ch2 == -1)
10321 return (total);
10322 if (ctxt->value == NULL)
10323 return (total);
10324
10325 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010326
10327#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010328 /*
10329 * Hum are we filtering the result of an XPointer expression
10330 */
10331 if (ctxt->value->type == XPATH_LOCATIONSET) {
10332 xmlLocationSetPtr newlocset = NULL;
10333 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010334
Daniel Veillardf06307e2001-07-03 10:35:50 +000010335 /*
10336 * Extract the old locset, and then evaluate the result of the
10337 * expression for all the element in the locset. use it to grow
10338 * up a new locset.
10339 */
10340 CHECK_TYPE0(XPATH_LOCATIONSET);
10341 obj = valuePop(ctxt);
10342 oldlocset = obj->user;
10343 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010344
Daniel Veillardf06307e2001-07-03 10:35:50 +000010345 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10346 ctxt->context->contextSize = 0;
10347 ctxt->context->proximityPosition = 0;
10348 if (op->ch2 != -1)
10349 total +=
10350 xmlXPathCompOpEval(ctxt,
10351 &comp->steps[op->ch2]);
10352 res = valuePop(ctxt);
10353 if (res != NULL)
10354 xmlXPathFreeObject(res);
10355 valuePush(ctxt, obj);
10356 CHECK_ERROR0;
10357 return (total);
10358 }
10359 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010360
Daniel Veillardf06307e2001-07-03 10:35:50 +000010361 for (i = 0; i < oldlocset->locNr; i++) {
10362 /*
10363 * Run the evaluation with a node list made of a
10364 * single item in the nodelocset.
10365 */
10366 ctxt->context->node = oldlocset->locTab[i]->user;
10367 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10368 valuePush(ctxt, tmp);
10369 ctxt->context->contextSize = oldlocset->locNr;
10370 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010371
Daniel Veillardf06307e2001-07-03 10:35:50 +000010372 if (op->ch2 != -1)
10373 total +=
10374 xmlXPathCompOpEval(ctxt,
10375 &comp->steps[op->ch2]);
10376 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010377
Daniel Veillardf06307e2001-07-03 10:35:50 +000010378 /*
10379 * The result of the evaluation need to be tested to
10380 * decided whether the filter succeeded or not
10381 */
10382 res = valuePop(ctxt);
10383 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10384 xmlXPtrLocationSetAdd(newlocset,
10385 xmlXPathObjectCopy
10386 (oldlocset->locTab[i]));
10387 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010388
Daniel Veillardf06307e2001-07-03 10:35:50 +000010389 /*
10390 * Cleanup
10391 */
10392 if (res != NULL)
10393 xmlXPathFreeObject(res);
10394 if (ctxt->value == tmp) {
10395 res = valuePop(ctxt);
10396 xmlXPathFreeObject(res);
10397 }
10398
10399 ctxt->context->node = NULL;
10400 }
10401
10402 /*
10403 * The result is used as the new evaluation locset.
10404 */
10405 xmlXPathFreeObject(obj);
10406 ctxt->context->node = NULL;
10407 ctxt->context->contextSize = -1;
10408 ctxt->context->proximityPosition = -1;
10409 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10410 ctxt->context->node = oldnode;
10411 return (total);
10412 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010413#endif /* LIBXML_XPTR_ENABLED */
10414
Daniel Veillardf06307e2001-07-03 10:35:50 +000010415 /*
10416 * Extract the old set, and then evaluate the result of the
10417 * expression for all the element in the set. use it to grow
10418 * up a new set.
10419 */
10420 CHECK_TYPE0(XPATH_NODESET);
10421 obj = valuePop(ctxt);
10422 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010423
Daniel Veillardf06307e2001-07-03 10:35:50 +000010424 oldnode = ctxt->context->node;
10425 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010426
Daniel Veillardf06307e2001-07-03 10:35:50 +000010427 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10428 ctxt->context->contextSize = 0;
10429 ctxt->context->proximityPosition = 0;
10430 if (op->ch2 != -1)
10431 total +=
10432 xmlXPathCompOpEval(ctxt,
10433 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010434 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010435 res = valuePop(ctxt);
10436 if (res != NULL)
10437 xmlXPathFreeObject(res);
10438 valuePush(ctxt, obj);
10439 ctxt->context->node = oldnode;
10440 CHECK_ERROR0;
10441 } else {
10442 /*
10443 * Initialize the new set.
10444 */
10445 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010446
Daniel Veillardf06307e2001-07-03 10:35:50 +000010447 for (i = 0; i < oldset->nodeNr; i++) {
10448 /*
10449 * Run the evaluation with a node list made of
10450 * a single item in the nodeset.
10451 */
10452 ctxt->context->node = oldset->nodeTab[i];
10453 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10454 valuePush(ctxt, tmp);
10455 ctxt->context->contextSize = oldset->nodeNr;
10456 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010457
Daniel Veillardf06307e2001-07-03 10:35:50 +000010458 if (op->ch2 != -1)
10459 total +=
10460 xmlXPathCompOpEval(ctxt,
10461 &comp->steps[op->ch2]);
10462 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010463
Daniel Veillardf06307e2001-07-03 10:35:50 +000010464 /*
10465 * The result of the evaluation need to be tested to
10466 * decided whether the filter succeeded or not
10467 */
10468 res = valuePop(ctxt);
10469 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10470 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10471 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010472
Daniel Veillardf06307e2001-07-03 10:35:50 +000010473 /*
10474 * Cleanup
10475 */
10476 if (res != NULL)
10477 xmlXPathFreeObject(res);
10478 if (ctxt->value == tmp) {
10479 res = valuePop(ctxt);
10480 xmlXPathFreeObject(res);
10481 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010482
Daniel Veillardf06307e2001-07-03 10:35:50 +000010483 ctxt->context->node = NULL;
10484 }
10485
10486 /*
10487 * The result is used as the new evaluation set.
10488 */
10489 xmlXPathFreeObject(obj);
10490 ctxt->context->node = NULL;
10491 ctxt->context->contextSize = -1;
10492 ctxt->context->proximityPosition = -1;
10493 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10494 }
10495 ctxt->context->node = oldnode;
10496 return (total);
10497 }
10498 case XPATH_OP_SORT:
10499 if (op->ch1 != -1)
10500 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010501 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010502 if ((ctxt->value != NULL) &&
10503 (ctxt->value->type == XPATH_NODESET) &&
10504 (ctxt->value->nodesetval != NULL))
10505 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10506 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010507#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010508 case XPATH_OP_RANGETO:{
10509 xmlXPathObjectPtr range;
10510 xmlXPathObjectPtr res, obj;
10511 xmlXPathObjectPtr tmp;
10512 xmlLocationSetPtr newset = NULL;
10513 xmlNodeSetPtr oldset;
10514 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010515
Daniel Veillardf06307e2001-07-03 10:35:50 +000010516 if (op->ch1 != -1)
10517 total +=
10518 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10519 if (op->ch2 == -1)
10520 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010521
Daniel Veillardf06307e2001-07-03 10:35:50 +000010522 CHECK_TYPE0(XPATH_NODESET);
10523 obj = valuePop(ctxt);
10524 oldset = obj->nodesetval;
10525 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010526
Daniel Veillardf06307e2001-07-03 10:35:50 +000010527 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010528
Daniel Veillardf06307e2001-07-03 10:35:50 +000010529 if (oldset != NULL) {
10530 for (i = 0; i < oldset->nodeNr; i++) {
10531 /*
10532 * Run the evaluation with a node list made of a single item
10533 * in the nodeset.
10534 */
10535 ctxt->context->node = oldset->nodeTab[i];
10536 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10537 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010538
Daniel Veillardf06307e2001-07-03 10:35:50 +000010539 if (op->ch2 != -1)
10540 total +=
10541 xmlXPathCompOpEval(ctxt,
10542 &comp->steps[op->ch2]);
10543 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010544
Daniel Veillardf06307e2001-07-03 10:35:50 +000010545 /*
10546 * The result of the evaluation need to be tested to
10547 * decided whether the filter succeeded or not
10548 */
10549 res = valuePop(ctxt);
10550 range =
10551 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10552 res);
10553 if (range != NULL) {
10554 xmlXPtrLocationSetAdd(newset, range);
10555 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010556
Daniel Veillardf06307e2001-07-03 10:35:50 +000010557 /*
10558 * Cleanup
10559 */
10560 if (res != NULL)
10561 xmlXPathFreeObject(res);
10562 if (ctxt->value == tmp) {
10563 res = valuePop(ctxt);
10564 xmlXPathFreeObject(res);
10565 }
10566
10567 ctxt->context->node = NULL;
10568 }
10569 }
10570
10571 /*
10572 * The result is used as the new evaluation set.
10573 */
10574 xmlXPathFreeObject(obj);
10575 ctxt->context->node = NULL;
10576 ctxt->context->contextSize = -1;
10577 ctxt->context->proximityPosition = -1;
10578 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
10579 return (total);
10580 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010581#endif /* LIBXML_XPTR_ENABLED */
10582 }
10583 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010584 "XPath: unknown precompiled operation %d\n", op->op);
10585 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010586}
10587
10588/**
10589 * xmlXPathRunEval:
10590 * @ctxt: the XPath parser context with the compiled expression
10591 *
10592 * Evaluate the Precompiled XPath expression in the given context.
10593 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010594static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010595xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10596 xmlXPathCompExprPtr comp;
10597
10598 if ((ctxt == NULL) || (ctxt->comp == NULL))
10599 return;
10600
10601 if (ctxt->valueTab == NULL) {
10602 /* Allocate the value stack */
10603 ctxt->valueTab = (xmlXPathObjectPtr *)
10604 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10605 if (ctxt->valueTab == NULL) {
10606 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010607 }
10608 ctxt->valueNr = 0;
10609 ctxt->valueMax = 10;
10610 ctxt->value = NULL;
10611 }
10612 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000010613 if(comp->last < 0) {
10614 xmlGenericError(xmlGenericErrorContext,
10615 "xmlXPathRunEval: last is less than zero\n");
10616 return;
10617 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010618 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10619}
10620
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010621/************************************************************************
10622 * *
10623 * Public interfaces *
10624 * *
10625 ************************************************************************/
10626
10627/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010628 * xmlXPathEvalPredicate:
10629 * @ctxt: the XPath context
10630 * @res: the Predicate Expression evaluation result
10631 *
10632 * Evaluate a predicate result for the current node.
10633 * A PredicateExpr is evaluated by evaluating the Expr and converting
10634 * the result to a boolean. If the result is a number, the result will
10635 * be converted to true if the number is equal to the position of the
10636 * context node in the context node list (as returned by the position
10637 * function) and will be converted to false otherwise; if the result
10638 * is not a number, then the result will be converted as if by a call
10639 * to the boolean function.
10640 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010641 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010642 */
10643int
10644xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
10645 if (res == NULL) return(0);
10646 switch (res->type) {
10647 case XPATH_BOOLEAN:
10648 return(res->boolval);
10649 case XPATH_NUMBER:
10650 return(res->floatval == ctxt->proximityPosition);
10651 case XPATH_NODESET:
10652 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010653 if (res->nodesetval == NULL)
10654 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010655 return(res->nodesetval->nodeNr != 0);
10656 case XPATH_STRING:
10657 return((res->stringval != NULL) &&
10658 (xmlStrlen(res->stringval) != 0));
10659 default:
10660 STRANGE
10661 }
10662 return(0);
10663}
10664
10665/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010666 * xmlXPathEvaluatePredicateResult:
10667 * @ctxt: the XPath Parser context
10668 * @res: the Predicate Expression evaluation result
10669 *
10670 * Evaluate a predicate result for the current node.
10671 * A PredicateExpr is evaluated by evaluating the Expr and converting
10672 * the result to a boolean. If the result is a number, the result will
10673 * be converted to true if the number is equal to the position of the
10674 * context node in the context node list (as returned by the position
10675 * function) and will be converted to false otherwise; if the result
10676 * is not a number, then the result will be converted as if by a call
10677 * to the boolean function.
10678 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010679 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010680 */
10681int
10682xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10683 xmlXPathObjectPtr res) {
10684 if (res == NULL) return(0);
10685 switch (res->type) {
10686 case XPATH_BOOLEAN:
10687 return(res->boolval);
10688 case XPATH_NUMBER:
10689 return(res->floatval == ctxt->context->proximityPosition);
10690 case XPATH_NODESET:
10691 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000010692 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000010693 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010694 return(res->nodesetval->nodeNr != 0);
10695 case XPATH_STRING:
10696 return((res->stringval != NULL) &&
10697 (xmlStrlen(res->stringval) != 0));
10698 default:
10699 STRANGE
10700 }
10701 return(0);
10702}
10703
10704/**
10705 * xmlXPathCompile:
10706 * @str: the XPath expression
10707 *
10708 * Compile an XPath expression
10709 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000010710 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010711 * the caller has to free the object.
10712 */
10713xmlXPathCompExprPtr
10714xmlXPathCompile(const xmlChar *str) {
10715 xmlXPathParserContextPtr ctxt;
10716 xmlXPathCompExprPtr comp;
10717
10718 xmlXPathInit();
10719
10720 ctxt = xmlXPathNewParserContext(str, NULL);
10721 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010722
Daniel Veillard40af6492001-04-22 08:50:55 +000010723 if (*ctxt->cur != 0) {
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010724 /*
10725 * aleksey: in some cases this line prints *second* error message
10726 * (see bug #78858) and probably this should be fixed.
10727 * However, we are not sure that all error messages are printed
10728 * out in other places. It's not critical so we leave it as-is for now
10729 */
Daniel Veillard40af6492001-04-22 08:50:55 +000010730 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10731 comp = NULL;
10732 } else {
10733 comp = ctxt->comp;
10734 ctxt->comp = NULL;
10735 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010736 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010737 if (comp != NULL) {
Daniel Veillardceb09b92002-10-04 11:46:37 +000010738 comp->expr = xmlStrdup(str);
10739#ifdef DEBUG_EVAL_COUNTS
Daniel Veillardf06307e2001-07-03 10:35:50 +000010740 comp->string = xmlStrdup(str);
10741 comp->nb = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010742#endif
Daniel Veillardceb09b92002-10-04 11:46:37 +000010743 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010744 return(comp);
10745}
10746
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010747/**
10748 * xmlXPathCompiledEval:
10749 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000010750 * @ctx: the XPath context
10751 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010752 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000010753 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010754 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000010755 * the caller has to free the object.
10756 */
10757xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010758xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000010759 xmlXPathParserContextPtr ctxt;
10760 xmlXPathObjectPtr res, tmp, init = NULL;
10761 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000010762#ifndef LIBXML_THREAD_ENABLED
10763 static int reentance = 0;
10764#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010765
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010766 if ((comp == NULL) || (ctx == NULL))
10767 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010768 xmlXPathInit();
10769
10770 CHECK_CONTEXT(ctx)
10771
Daniel Veillard81463942001-10-16 12:34:39 +000010772#ifndef LIBXML_THREAD_ENABLED
10773 reentance++;
10774 if (reentance > 1)
10775 xmlXPathDisableOptimizer = 1;
10776#endif
10777
Daniel Veillardf06307e2001-07-03 10:35:50 +000010778#ifdef DEBUG_EVAL_COUNTS
10779 comp->nb++;
10780 if ((comp->string != NULL) && (comp->nb > 100)) {
10781 fprintf(stderr, "100 x %s\n", comp->string);
10782 comp->nb = 0;
10783 }
10784#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010785 ctxt = xmlXPathCompParserContext(comp, ctx);
10786 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010787
10788 if (ctxt->value == NULL) {
10789 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010790 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000010791 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000010792 } else {
10793 res = valuePop(ctxt);
10794 }
10795
Daniel Veillardf06307e2001-07-03 10:35:50 +000010796
Owen Taylor3473f882001-02-23 17:55:21 +000010797 do {
10798 tmp = valuePop(ctxt);
10799 if (tmp != NULL) {
10800 if (tmp != init)
10801 stack++;
10802 xmlXPathFreeObject(tmp);
10803 }
10804 } while (tmp != NULL);
10805 if ((stack != 0) && (res != NULL)) {
10806 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010807 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000010808 stack);
10809 }
10810 if (ctxt->error != XPATH_EXPRESSION_OK) {
10811 xmlXPathFreeObject(res);
10812 res = NULL;
10813 }
10814
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010815
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010816 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010817 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000010818#ifndef LIBXML_THREAD_ENABLED
10819 reentance--;
10820#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010821 return(res);
10822}
10823
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010824/**
10825 * xmlXPathEvalExpr:
10826 * @ctxt: the XPath Parser context
10827 *
10828 * Parse and evaluate an XPath expression in the given context,
10829 * then push the result on the context stack
10830 */
10831void
10832xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
10833 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010834 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010835 xmlXPathRunEval(ctxt);
10836}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010837
10838/**
10839 * xmlXPathEval:
10840 * @str: the XPath expression
10841 * @ctx: the XPath context
10842 *
10843 * Evaluate the XPath Location Path in the given context.
10844 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010845 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010846 * the caller has to free the object.
10847 */
10848xmlXPathObjectPtr
10849xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
10850 xmlXPathParserContextPtr ctxt;
10851 xmlXPathObjectPtr res, tmp, init = NULL;
10852 int stack = 0;
10853
10854 xmlXPathInit();
10855
10856 CHECK_CONTEXT(ctx)
10857
10858 ctxt = xmlXPathNewParserContext(str, ctx);
10859 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010860
10861 if (ctxt->value == NULL) {
10862 xmlGenericError(xmlGenericErrorContext,
10863 "xmlXPathEval: evaluation failed\n");
10864 res = NULL;
10865 } else if (*ctxt->cur != 0) {
10866 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10867 res = NULL;
10868 } else {
10869 res = valuePop(ctxt);
10870 }
10871
10872 do {
10873 tmp = valuePop(ctxt);
10874 if (tmp != NULL) {
10875 if (tmp != init)
10876 stack++;
10877 xmlXPathFreeObject(tmp);
10878 }
10879 } while (tmp != NULL);
10880 if ((stack != 0) && (res != NULL)) {
10881 xmlGenericError(xmlGenericErrorContext,
10882 "xmlXPathEval: %d object left on the stack\n",
10883 stack);
10884 }
10885 if (ctxt->error != XPATH_EXPRESSION_OK) {
10886 xmlXPathFreeObject(res);
10887 res = NULL;
10888 }
10889
Owen Taylor3473f882001-02-23 17:55:21 +000010890 xmlXPathFreeParserContext(ctxt);
10891 return(res);
10892}
10893
10894/**
10895 * xmlXPathEvalExpression:
10896 * @str: the XPath expression
10897 * @ctxt: the XPath context
10898 *
10899 * Evaluate the XPath expression in the given context.
10900 *
10901 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
10902 * the caller has to free the object.
10903 */
10904xmlXPathObjectPtr
10905xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
10906 xmlXPathParserContextPtr pctxt;
10907 xmlXPathObjectPtr res, tmp;
10908 int stack = 0;
10909
10910 xmlXPathInit();
10911
10912 CHECK_CONTEXT(ctxt)
10913
10914 pctxt = xmlXPathNewParserContext(str, ctxt);
10915 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010916
10917 if (*pctxt->cur != 0) {
10918 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10919 res = NULL;
10920 } else {
10921 res = valuePop(pctxt);
10922 }
10923 do {
10924 tmp = valuePop(pctxt);
10925 if (tmp != NULL) {
10926 xmlXPathFreeObject(tmp);
10927 stack++;
10928 }
10929 } while (tmp != NULL);
10930 if ((stack != 0) && (res != NULL)) {
10931 xmlGenericError(xmlGenericErrorContext,
10932 "xmlXPathEvalExpression: %d object left on the stack\n",
10933 stack);
10934 }
10935 xmlXPathFreeParserContext(pctxt);
10936 return(res);
10937}
10938
Daniel Veillard42766c02002-08-22 20:52:17 +000010939/************************************************************************
10940 * *
10941 * Extra functions not pertaining to the XPath spec *
10942 * *
10943 ************************************************************************/
10944/**
10945 * xmlXPathEscapeUriFunction:
10946 * @ctxt: the XPath Parser context
10947 * @nargs: the number of arguments
10948 *
10949 * Implement the escape-uri() XPath function
10950 * string escape-uri(string $str, bool $escape-reserved)
10951 *
10952 * This function applies the URI escaping rules defined in section 2 of [RFC
10953 * 2396] to the string supplied as $uri-part, which typically represents all
10954 * or part of a URI. The effect of the function is to replace any special
10955 * character in the string by an escape sequence of the form %xx%yy...,
10956 * where xxyy... is the hexadecimal representation of the octets used to
10957 * represent the character in UTF-8.
10958 *
10959 * The set of characters that are escaped depends on the setting of the
10960 * boolean argument $escape-reserved.
10961 *
10962 * If $escape-reserved is true, all characters are escaped other than lower
10963 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
10964 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
10965 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
10966 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
10967 * A-F).
10968 *
10969 * If $escape-reserved is false, the behavior differs in that characters
10970 * referred to in [RFC 2396] as reserved characters are not escaped. These
10971 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
10972 *
10973 * [RFC 2396] does not define whether escaped URIs should use lower case or
10974 * upper case for hexadecimal digits. To ensure that escaped URIs can be
10975 * compared using string comparison functions, this function must always use
10976 * the upper-case letters A-F.
10977 *
10978 * Generally, $escape-reserved should be set to true when escaping a string
10979 * that is to form a single part of a URI, and to false when escaping an
10980 * entire URI or URI reference.
10981 *
10982 * In the case of non-ascii characters, the string is encoded according to
10983 * utf-8 and then converted according to RFC 2396.
10984 *
10985 * Examples
10986 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
10987 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
10988 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
10989 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
10990 *
10991 */
Daniel Veillard118aed72002-09-24 14:13:13 +000010992static void
Daniel Veillard42766c02002-08-22 20:52:17 +000010993xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
10994 xmlXPathObjectPtr str;
10995 int escape_reserved;
10996 xmlBufferPtr target;
10997 xmlChar *cptr;
10998 xmlChar escape[4];
10999
11000 CHECK_ARITY(2);
11001
11002 escape_reserved = xmlXPathPopBoolean(ctxt);
11003
11004 CAST_TO_STRING;
11005 str = valuePop(ctxt);
11006
11007 target = xmlBufferCreate();
11008
11009 escape[0] = '%';
11010 escape[3] = 0;
11011
11012 if (target) {
11013 for (cptr = str->stringval; *cptr; cptr++) {
11014 if ((*cptr >= 'A' && *cptr <= 'Z') ||
11015 (*cptr >= 'a' && *cptr <= 'z') ||
11016 (*cptr >= '0' && *cptr <= '9') ||
11017 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
11018 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
11019 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
11020 (*cptr == '%' &&
11021 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
11022 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
11023 (cptr[1] >= '0' && cptr[1] <= '9')) &&
11024 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
11025 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
11026 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
11027 (!escape_reserved &&
11028 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
11029 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
11030 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
11031 *cptr == ','))) {
11032 xmlBufferAdd(target, cptr, 1);
11033 } else {
11034 if ((*cptr >> 4) < 10)
11035 escape[1] = '0' + (*cptr >> 4);
11036 else
11037 escape[1] = 'A' - 10 + (*cptr >> 4);
11038 if ((*cptr & 0xF) < 10)
11039 escape[2] = '0' + (*cptr & 0xF);
11040 else
11041 escape[2] = 'A' - 10 + (*cptr & 0xF);
11042
11043 xmlBufferAdd(target, &escape[0], 3);
11044 }
11045 }
11046 }
11047 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
11048 xmlBufferFree(target);
11049 xmlXPathFreeObject(str);
11050}
11051
Owen Taylor3473f882001-02-23 17:55:21 +000011052/**
11053 * xmlXPathRegisterAllFunctions:
11054 * @ctxt: the XPath context
11055 *
11056 * Registers all default XPath functions in this context
11057 */
11058void
11059xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
11060{
11061 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
11062 xmlXPathBooleanFunction);
11063 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
11064 xmlXPathCeilingFunction);
11065 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
11066 xmlXPathCountFunction);
11067 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
11068 xmlXPathConcatFunction);
11069 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
11070 xmlXPathContainsFunction);
11071 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
11072 xmlXPathIdFunction);
11073 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
11074 xmlXPathFalseFunction);
11075 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
11076 xmlXPathFloorFunction);
11077 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
11078 xmlXPathLastFunction);
11079 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
11080 xmlXPathLangFunction);
11081 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
11082 xmlXPathLocalNameFunction);
11083 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
11084 xmlXPathNotFunction);
11085 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
11086 xmlXPathNameFunction);
11087 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
11088 xmlXPathNamespaceURIFunction);
11089 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
11090 xmlXPathNormalizeFunction);
11091 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
11092 xmlXPathNumberFunction);
11093 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
11094 xmlXPathPositionFunction);
11095 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
11096 xmlXPathRoundFunction);
11097 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
11098 xmlXPathStringFunction);
11099 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
11100 xmlXPathStringLengthFunction);
11101 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
11102 xmlXPathStartsWithFunction);
11103 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
11104 xmlXPathSubstringFunction);
11105 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
11106 xmlXPathSubstringBeforeFunction);
11107 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
11108 xmlXPathSubstringAfterFunction);
11109 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
11110 xmlXPathSumFunction);
11111 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
11112 xmlXPathTrueFunction);
11113 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
11114 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000011115
11116 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
11117 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
11118 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000011119}
11120
11121#endif /* LIBXML_XPATH_ENABLED */