blob: 65ca1800020900a402cee413d91d4a2de2068241 [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
Owen Taylor3473f882001-02-23 17:55:21 +000020#include <string.h>
21
22#ifdef HAVE_SYS_TYPES_H
23#include <sys/types.h>
24#endif
25#ifdef HAVE_MATH_H
26#include <math.h>
27#endif
28#ifdef HAVE_FLOAT_H
29#include <float.h>
30#endif
Owen Taylor3473f882001-02-23 17:55:21 +000031#ifdef HAVE_CTYPE_H
32#include <ctype.h>
33#endif
Daniel Veillard5792e162001-04-30 17:44:45 +000034#ifdef HAVE_SIGNAL_H
Daniel Veillardb45c43b2001-04-28 17:02:11 +000035#include <signal.h>
Daniel Veillardb45c43b2001-04-28 17:02:11 +000036#endif
Owen Taylor3473f882001-02-23 17:55:21 +000037
38#include <libxml/xmlmemory.h>
39#include <libxml/tree.h>
40#include <libxml/valid.h>
41#include <libxml/xpath.h>
42#include <libxml/xpathInternals.h>
43#include <libxml/parserInternals.h>
44#include <libxml/hash.h>
45#ifdef LIBXML_XPTR_ENABLED
46#include <libxml/xpointer.h>
47#endif
48#ifdef LIBXML_DEBUG_ENABLED
49#include <libxml/debugXML.h>
50#endif
51#include <libxml/xmlerror.h>
Daniel Veillard81463942001-10-16 12:34:39 +000052#include <libxml/threads.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000053#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000054
Daniel Veillard4432df22003-09-28 18:58:27 +000055#if defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_XPATH_ENABLED)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000056/************************************************************************
57 * *
58 * Floating point stuff *
59 * *
60 ************************************************************************/
61
Daniel Veillardc0631a62001-09-20 13:56:06 +000062#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +000063#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +000064#endif
Daniel Veillardcda96922001-08-21 10:56:31 +000065#include "trionan.c"
66
Owen Taylor3473f882001-02-23 17:55:21 +000067/*
Owen Taylor3473f882001-02-23 17:55:21 +000068 * The lack of portability of this section of the libc is annoying !
69 */
70double xmlXPathNAN = 0;
71double xmlXPathPINF = 1;
72double xmlXPathNINF = -1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +000073double xmlXPathNZERO = 0;
Daniel Veillard20ee8c02001-10-05 09:18:14 +000074static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000075
Owen Taylor3473f882001-02-23 17:55:21 +000076/**
77 * xmlXPathInit:
78 *
79 * Initialize the XPath environment
80 */
81void
82xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +000083 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +000084
Bjorn Reese45029602001-08-21 09:23:53 +000085 xmlXPathPINF = trio_pinf();
86 xmlXPathNINF = trio_ninf();
87 xmlXPathNAN = trio_nan();
Daniel Veillard5fc1f082002-03-27 09:05:40 +000088 xmlXPathNZERO = trio_nzero();
Owen Taylor3473f882001-02-23 17:55:21 +000089
Daniel Veillard20ee8c02001-10-05 09:18:14 +000090 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000091}
92
Daniel Veillardcda96922001-08-21 10:56:31 +000093/**
94 * xmlXPathIsNaN:
95 * @val: a double value
96 *
97 * Provides a portable isnan() function to detect whether a double
98 * is a NotaNumber. Based on trio code
99 * http://sourceforge.net/projects/ctrio/
100 *
101 * Returns 1 if the value is a NaN, 0 otherwise
102 */
103int
104xmlXPathIsNaN(double val) {
105 return(trio_isnan(val));
106}
107
108/**
109 * xmlXPathIsInf:
110 * @val: a double value
111 *
112 * Provides a portable isinf() function to detect whether a double
113 * is a +Infinite or -Infinite. Based on trio code
114 * http://sourceforge.net/projects/ctrio/
115 *
116 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
117 */
118int
119xmlXPathIsInf(double val) {
120 return(trio_isinf(val));
121}
122
Daniel Veillard4432df22003-09-28 18:58:27 +0000123#endif /* SCHEMAS or XPATH */
124#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000125/**
126 * xmlXPathGetSign:
127 * @val: a double value
128 *
129 * Provides a portable function to detect the sign of a double
130 * Modified from trio code
131 * http://sourceforge.net/projects/ctrio/
132 *
133 * Returns 1 if the value is Negative, 0 if positive
134 */
Daniel Veillard21458c82002-03-27 16:12:22 +0000135static int
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000136xmlXPathGetSign(double val) {
Daniel Veillard21458c82002-03-27 16:12:22 +0000137 return(trio_signbit(val));
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000138}
139
140
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000141/*
142 * TODO: when compatibility allows remove all "fake node libxslt" strings
143 * the test should just be name[0] = ' '
144 */
145/* #define DEBUG */
146/* #define DEBUG_STEP */
147/* #define DEBUG_STEP_NTH */
148/* #define DEBUG_EXPR */
149/* #define DEBUG_EVAL_COUNTS */
150
151static xmlNs xmlXPathXMLNamespaceStruct = {
152 NULL,
153 XML_NAMESPACE_DECL,
154 XML_XML_NAMESPACE,
155 BAD_CAST "xml",
156 NULL
157};
158static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
159#ifndef LIBXML_THREAD_ENABLED
160/*
161 * Optimizer is disabled only when threaded apps are detected while
162 * the library ain't compiled for thread safety.
163 */
164static int xmlXPathDisableOptimizer = 0;
165#endif
166
Owen Taylor3473f882001-02-23 17:55:21 +0000167/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000168 * *
169 * Parser Types *
170 * *
171 ************************************************************************/
172
173/*
174 * Types are private:
175 */
176
177typedef enum {
178 XPATH_OP_END=0,
179 XPATH_OP_AND,
180 XPATH_OP_OR,
181 XPATH_OP_EQUAL,
182 XPATH_OP_CMP,
183 XPATH_OP_PLUS,
184 XPATH_OP_MULT,
185 XPATH_OP_UNION,
186 XPATH_OP_ROOT,
187 XPATH_OP_NODE,
188 XPATH_OP_RESET,
189 XPATH_OP_COLLECT,
190 XPATH_OP_VALUE,
191 XPATH_OP_VARIABLE,
192 XPATH_OP_FUNCTION,
193 XPATH_OP_ARG,
194 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000195 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000196 XPATH_OP_SORT
197#ifdef LIBXML_XPTR_ENABLED
198 ,XPATH_OP_RANGETO
199#endif
200} xmlXPathOp;
201
202typedef enum {
203 AXIS_ANCESTOR = 1,
204 AXIS_ANCESTOR_OR_SELF,
205 AXIS_ATTRIBUTE,
206 AXIS_CHILD,
207 AXIS_DESCENDANT,
208 AXIS_DESCENDANT_OR_SELF,
209 AXIS_FOLLOWING,
210 AXIS_FOLLOWING_SIBLING,
211 AXIS_NAMESPACE,
212 AXIS_PARENT,
213 AXIS_PRECEDING,
214 AXIS_PRECEDING_SIBLING,
215 AXIS_SELF
216} xmlXPathAxisVal;
217
218typedef enum {
219 NODE_TEST_NONE = 0,
220 NODE_TEST_TYPE = 1,
221 NODE_TEST_PI = 2,
222 NODE_TEST_ALL = 3,
223 NODE_TEST_NS = 4,
224 NODE_TEST_NAME = 5
225} xmlXPathTestVal;
226
227typedef enum {
228 NODE_TYPE_NODE = 0,
229 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
230 NODE_TYPE_TEXT = XML_TEXT_NODE,
231 NODE_TYPE_PI = XML_PI_NODE
232} xmlXPathTypeVal;
233
234
235typedef struct _xmlXPathStepOp xmlXPathStepOp;
236typedef xmlXPathStepOp *xmlXPathStepOpPtr;
237struct _xmlXPathStepOp {
238 xmlXPathOp op;
239 int ch1;
240 int ch2;
241 int value;
242 int value2;
243 int value3;
244 void *value4;
245 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000246 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000247 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000248};
249
250struct _xmlXPathCompExpr {
251 int nbStep;
252 int maxStep;
253 xmlXPathStepOp *steps; /* ops for computation */
254 int last;
Daniel Veillard118aed72002-09-24 14:13:13 +0000255 xmlChar *expr;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000256#ifdef DEBUG_EVAL_COUNTS
257 int nb;
258 xmlChar *string;
259#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000260};
261
262/************************************************************************
263 * *
264 * Parser Type functions *
265 * *
266 ************************************************************************/
267
268/**
269 * xmlXPathNewCompExpr:
270 *
271 * Create a new Xpath component
272 *
273 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
274 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000275static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000276xmlXPathNewCompExpr(void) {
277 xmlXPathCompExprPtr cur;
278
279 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
280 if (cur == NULL) {
281 xmlGenericError(xmlGenericErrorContext,
282 "xmlXPathNewCompExpr : malloc failed\n");
283 return(NULL);
284 }
285 memset(cur, 0, sizeof(xmlXPathCompExpr));
286 cur->maxStep = 10;
287 cur->nbStep = 0;
288 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
289 sizeof(xmlXPathStepOp));
290 if (cur->steps == NULL) {
291 xmlGenericError(xmlGenericErrorContext,
292 "xmlXPathNewCompExpr : malloc failed\n");
293 xmlFree(cur);
294 return(NULL);
295 }
296 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
297 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000298#ifdef DEBUG_EVAL_COUNTS
299 cur->nb = 0;
300#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000301 return(cur);
302}
303
304/**
305 * xmlXPathFreeCompExpr:
306 * @comp: an XPATH comp
307 *
308 * Free up the memory allocated by @comp
309 */
310void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000311xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
312{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000313 xmlXPathStepOpPtr op;
314 int i;
315
316 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000317 return;
318 for (i = 0; i < comp->nbStep; i++) {
319 op = &comp->steps[i];
320 if (op->value4 != NULL) {
321 if (op->op == XPATH_OP_VALUE)
322 xmlXPathFreeObject(op->value4);
323 else
324 xmlFree(op->value4);
325 }
326 if (op->value5 != NULL)
327 xmlFree(op->value5);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000328 }
329 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000330 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000331 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000332#ifdef DEBUG_EVAL_COUNTS
333 if (comp->string != NULL) {
334 xmlFree(comp->string);
335 }
336#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000337 if (comp->expr != NULL) {
338 xmlFree(comp->expr);
339 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000340
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000341 xmlFree(comp);
342}
343
344/**
345 * xmlXPathCompExprAdd:
346 * @comp: the compiled expression
347 * @ch1: first child index
348 * @ch2: second child index
349 * @op: an op
350 * @value: the first int value
351 * @value2: the second int value
352 * @value3: the third int value
353 * @value4: the first string value
354 * @value5: the second string value
355 *
356 * Add an step to an XPath Compiled Expression
357 *
358 * Returns -1 in case of failure, the index otherwise
359 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000360static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000361xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
362 xmlXPathOp op, int value,
363 int value2, int value3, void *value4, void *value5) {
364 if (comp->nbStep >= comp->maxStep) {
365 xmlXPathStepOp *real;
366
367 comp->maxStep *= 2;
368 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
369 comp->maxStep * sizeof(xmlXPathStepOp));
370 if (real == NULL) {
371 comp->maxStep /= 2;
372 xmlGenericError(xmlGenericErrorContext,
373 "xmlXPathCompExprAdd : realloc failed\n");
374 return(-1);
375 }
376 comp->steps = real;
377 }
378 comp->last = comp->nbStep;
379 comp->steps[comp->nbStep].ch1 = ch1;
380 comp->steps[comp->nbStep].ch2 = ch2;
381 comp->steps[comp->nbStep].op = op;
382 comp->steps[comp->nbStep].value = value;
383 comp->steps[comp->nbStep].value2 = value2;
384 comp->steps[comp->nbStep].value3 = value3;
385 comp->steps[comp->nbStep].value4 = value4;
386 comp->steps[comp->nbStep].value5 = value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000387 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000388 return(comp->nbStep++);
389}
390
Daniel Veillardf06307e2001-07-03 10:35:50 +0000391/**
392 * xmlXPathCompSwap:
393 * @comp: the compiled expression
394 * @op: operation index
395 *
396 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000397 */
398static void
399xmlXPathCompSwap(xmlXPathStepOpPtr op) {
400 int tmp;
401
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000402#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000403 /*
404 * Since this manipulates possibly shared variables, this is
405 * disable if one detects that the library is used in a multithreaded
406 * application
407 */
408 if (xmlXPathDisableOptimizer)
409 return;
410#endif
411
Daniel Veillardf06307e2001-07-03 10:35:50 +0000412 tmp = op->ch1;
413 op->ch1 = op->ch2;
414 op->ch2 = tmp;
415}
416
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000417#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
418 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
419 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000420#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
421 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
422 (op), (val), (val2), (val3), (val4), (val5))
423
424#define PUSH_LEAVE_EXPR(op, val, val2) \
425xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
426
427#define PUSH_UNARY_EXPR(op, ch, val, val2) \
428xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
429
430#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
431xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), (val), (val2), 0 ,NULL ,NULL)
432
433/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000434 * *
435 * Debugging related functions *
436 * *
437 ************************************************************************/
438
439#define TODO \
440 xmlGenericError(xmlGenericErrorContext, \
441 "Unimplemented block at %s:%d\n", \
442 __FILE__, __LINE__);
443
444#define STRANGE \
445 xmlGenericError(xmlGenericErrorContext, \
446 "Internal error at %s:%d\n", \
447 __FILE__, __LINE__);
448
449#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000450static void
451xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000452 int i;
453 char shift[100];
454
455 for (i = 0;((i < depth) && (i < 25));i++)
456 shift[2 * i] = shift[2 * i + 1] = ' ';
457 shift[2 * i] = shift[2 * i + 1] = 0;
458 if (cur == NULL) {
459 fprintf(output, shift);
460 fprintf(output, "Node is NULL !\n");
461 return;
462
463 }
464
465 if ((cur->type == XML_DOCUMENT_NODE) ||
466 (cur->type == XML_HTML_DOCUMENT_NODE)) {
467 fprintf(output, shift);
468 fprintf(output, " /\n");
469 } else if (cur->type == XML_ATTRIBUTE_NODE)
470 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
471 else
472 xmlDebugDumpOneNode(output, cur, depth);
473}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000474static void
475xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000476 xmlNodePtr tmp;
477 int i;
478 char shift[100];
479
480 for (i = 0;((i < depth) && (i < 25));i++)
481 shift[2 * i] = shift[2 * i + 1] = ' ';
482 shift[2 * i] = shift[2 * i + 1] = 0;
483 if (cur == NULL) {
484 fprintf(output, shift);
485 fprintf(output, "Node is NULL !\n");
486 return;
487
488 }
489
490 while (cur != NULL) {
491 tmp = cur;
492 cur = cur->next;
493 xmlDebugDumpOneNode(output, tmp, depth);
494 }
495}
Owen Taylor3473f882001-02-23 17:55:21 +0000496
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000497static void
498xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000499 int i;
500 char shift[100];
501
502 for (i = 0;((i < depth) && (i < 25));i++)
503 shift[2 * i] = shift[2 * i + 1] = ' ';
504 shift[2 * i] = shift[2 * i + 1] = 0;
505
506 if (cur == NULL) {
507 fprintf(output, shift);
508 fprintf(output, "NodeSet is NULL !\n");
509 return;
510
511 }
512
Daniel Veillard911f49a2001-04-07 15:39:35 +0000513 if (cur != NULL) {
514 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
515 for (i = 0;i < cur->nodeNr;i++) {
516 fprintf(output, shift);
517 fprintf(output, "%d", i + 1);
518 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
519 }
Owen Taylor3473f882001-02-23 17:55:21 +0000520 }
521}
522
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000523static void
524xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000525 int i;
526 char shift[100];
527
528 for (i = 0;((i < depth) && (i < 25));i++)
529 shift[2 * i] = shift[2 * i + 1] = ' ';
530 shift[2 * i] = shift[2 * i + 1] = 0;
531
532 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
533 fprintf(output, shift);
534 fprintf(output, "Value Tree is NULL !\n");
535 return;
536
537 }
538
539 fprintf(output, shift);
540 fprintf(output, "%d", i + 1);
541 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
542}
Owen Taylor3473f882001-02-23 17:55:21 +0000543#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000544static void
545xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000546 int i;
547 char shift[100];
548
549 for (i = 0;((i < depth) && (i < 25));i++)
550 shift[2 * i] = shift[2 * i + 1] = ' ';
551 shift[2 * i] = shift[2 * i + 1] = 0;
552
553 if (cur == NULL) {
554 fprintf(output, shift);
555 fprintf(output, "LocationSet is NULL !\n");
556 return;
557
558 }
559
560 for (i = 0;i < cur->locNr;i++) {
561 fprintf(output, shift);
562 fprintf(output, "%d : ", i + 1);
563 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
564 }
565}
Daniel Veillard017b1082001-06-21 11:20:21 +0000566#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000567
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000568/**
569 * xmlXPathDebugDumpObject:
570 * @output: the FILE * to dump the output
571 * @cur: the object to inspect
572 * @depth: indentation level
573 *
574 * Dump the content of the object for debugging purposes
575 */
576void
577xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000578 int i;
579 char shift[100];
580
581 for (i = 0;((i < depth) && (i < 25));i++)
582 shift[2 * i] = shift[2 * i + 1] = ' ';
583 shift[2 * i] = shift[2 * i + 1] = 0;
584
585 fprintf(output, shift);
586
587 if (cur == NULL) {
588 fprintf(output, "Object is empty (NULL)\n");
589 return;
590 }
591 switch(cur->type) {
592 case XPATH_UNDEFINED:
593 fprintf(output, "Object is uninitialized\n");
594 break;
595 case XPATH_NODESET:
596 fprintf(output, "Object is a Node Set :\n");
597 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
598 break;
599 case XPATH_XSLT_TREE:
600 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000601 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000602 break;
603 case XPATH_BOOLEAN:
604 fprintf(output, "Object is a Boolean : ");
605 if (cur->boolval) fprintf(output, "true\n");
606 else fprintf(output, "false\n");
607 break;
608 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +0000609 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000610 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000611 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000612 break;
613 case -1:
614 fprintf(output, "Object is a number : -Infinity\n");
615 break;
616 default:
Daniel Veillardcda96922001-08-21 10:56:31 +0000617 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000618 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +0000619 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
620 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000621 } else {
622 fprintf(output, "Object is a number : %0g\n", cur->floatval);
623 }
624 }
Owen Taylor3473f882001-02-23 17:55:21 +0000625 break;
626 case XPATH_STRING:
627 fprintf(output, "Object is a string : ");
628 xmlDebugDumpString(output, cur->stringval);
629 fprintf(output, "\n");
630 break;
631 case XPATH_POINT:
632 fprintf(output, "Object is a point : index %d in node", cur->index);
633 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
634 fprintf(output, "\n");
635 break;
636 case XPATH_RANGE:
637 if ((cur->user2 == NULL) ||
638 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
639 fprintf(output, "Object is a collapsed range :\n");
640 fprintf(output, shift);
641 if (cur->index >= 0)
642 fprintf(output, "index %d in ", cur->index);
643 fprintf(output, "node\n");
644 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
645 depth + 1);
646 } else {
647 fprintf(output, "Object is a range :\n");
648 fprintf(output, shift);
649 fprintf(output, "From ");
650 if (cur->index >= 0)
651 fprintf(output, "index %d in ", cur->index);
652 fprintf(output, "node\n");
653 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
654 depth + 1);
655 fprintf(output, shift);
656 fprintf(output, "To ");
657 if (cur->index2 >= 0)
658 fprintf(output, "index %d in ", cur->index2);
659 fprintf(output, "node\n");
660 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
661 depth + 1);
662 fprintf(output, "\n");
663 }
664 break;
665 case XPATH_LOCATIONSET:
666#if defined(LIBXML_XPTR_ENABLED)
667 fprintf(output, "Object is a Location Set:\n");
668 xmlXPathDebugDumpLocationSet(output,
669 (xmlLocationSetPtr) cur->user, depth);
670#endif
671 break;
672 case XPATH_USERS:
673 fprintf(output, "Object is user defined\n");
674 break;
675 }
676}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000677
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000678static void
679xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000680 xmlXPathStepOpPtr op, int depth) {
681 int i;
682 char shift[100];
683
684 for (i = 0;((i < depth) && (i < 25));i++)
685 shift[2 * i] = shift[2 * i + 1] = ' ';
686 shift[2 * i] = shift[2 * i + 1] = 0;
687
688 fprintf(output, shift);
689 if (op == NULL) {
690 fprintf(output, "Step is NULL\n");
691 return;
692 }
693 switch (op->op) {
694 case XPATH_OP_END:
695 fprintf(output, "END"); break;
696 case XPATH_OP_AND:
697 fprintf(output, "AND"); break;
698 case XPATH_OP_OR:
699 fprintf(output, "OR"); break;
700 case XPATH_OP_EQUAL:
701 if (op->value)
702 fprintf(output, "EQUAL =");
703 else
704 fprintf(output, "EQUAL !=");
705 break;
706 case XPATH_OP_CMP:
707 if (op->value)
708 fprintf(output, "CMP <");
709 else
710 fprintf(output, "CMP >");
711 if (!op->value2)
712 fprintf(output, "=");
713 break;
714 case XPATH_OP_PLUS:
715 if (op->value == 0)
716 fprintf(output, "PLUS -");
717 else if (op->value == 1)
718 fprintf(output, "PLUS +");
719 else if (op->value == 2)
720 fprintf(output, "PLUS unary -");
721 else if (op->value == 3)
722 fprintf(output, "PLUS unary - -");
723 break;
724 case XPATH_OP_MULT:
725 if (op->value == 0)
726 fprintf(output, "MULT *");
727 else if (op->value == 1)
728 fprintf(output, "MULT div");
729 else
730 fprintf(output, "MULT mod");
731 break;
732 case XPATH_OP_UNION:
733 fprintf(output, "UNION"); break;
734 case XPATH_OP_ROOT:
735 fprintf(output, "ROOT"); break;
736 case XPATH_OP_NODE:
737 fprintf(output, "NODE"); break;
738 case XPATH_OP_RESET:
739 fprintf(output, "RESET"); break;
740 case XPATH_OP_SORT:
741 fprintf(output, "SORT"); break;
742 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +0000743 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
744 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
745 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000746 const xmlChar *prefix = op->value4;
747 const xmlChar *name = op->value5;
748
749 fprintf(output, "COLLECT ");
750 switch (axis) {
751 case AXIS_ANCESTOR:
752 fprintf(output, " 'ancestors' "); break;
753 case AXIS_ANCESTOR_OR_SELF:
754 fprintf(output, " 'ancestors-or-self' "); break;
755 case AXIS_ATTRIBUTE:
756 fprintf(output, " 'attributes' "); break;
757 case AXIS_CHILD:
758 fprintf(output, " 'child' "); break;
759 case AXIS_DESCENDANT:
760 fprintf(output, " 'descendant' "); break;
761 case AXIS_DESCENDANT_OR_SELF:
762 fprintf(output, " 'descendant-or-self' "); break;
763 case AXIS_FOLLOWING:
764 fprintf(output, " 'following' "); break;
765 case AXIS_FOLLOWING_SIBLING:
766 fprintf(output, " 'following-siblings' "); break;
767 case AXIS_NAMESPACE:
768 fprintf(output, " 'namespace' "); break;
769 case AXIS_PARENT:
770 fprintf(output, " 'parent' "); break;
771 case AXIS_PRECEDING:
772 fprintf(output, " 'preceding' "); break;
773 case AXIS_PRECEDING_SIBLING:
774 fprintf(output, " 'preceding-sibling' "); break;
775 case AXIS_SELF:
776 fprintf(output, " 'self' "); break;
777 }
778 switch (test) {
779 case NODE_TEST_NONE:
780 fprintf(output, "'none' "); break;
781 case NODE_TEST_TYPE:
782 fprintf(output, "'type' "); break;
783 case NODE_TEST_PI:
784 fprintf(output, "'PI' "); break;
785 case NODE_TEST_ALL:
786 fprintf(output, "'all' "); break;
787 case NODE_TEST_NS:
788 fprintf(output, "'namespace' "); break;
789 case NODE_TEST_NAME:
790 fprintf(output, "'name' "); break;
791 }
792 switch (type) {
793 case NODE_TYPE_NODE:
794 fprintf(output, "'node' "); break;
795 case NODE_TYPE_COMMENT:
796 fprintf(output, "'comment' "); break;
797 case NODE_TYPE_TEXT:
798 fprintf(output, "'text' "); break;
799 case NODE_TYPE_PI:
800 fprintf(output, "'PI' "); break;
801 }
802 if (prefix != NULL)
803 fprintf(output, "%s:", prefix);
804 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +0000805 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000806 break;
807
808 }
809 case XPATH_OP_VALUE: {
810 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
811
812 fprintf(output, "ELEM ");
813 xmlXPathDebugDumpObject(output, object, 0);
814 goto finish;
815 }
816 case XPATH_OP_VARIABLE: {
817 const xmlChar *prefix = op->value5;
818 const xmlChar *name = op->value4;
819
820 if (prefix != NULL)
821 fprintf(output, "VARIABLE %s:%s", prefix, name);
822 else
823 fprintf(output, "VARIABLE %s", name);
824 break;
825 }
826 case XPATH_OP_FUNCTION: {
827 int nbargs = op->value;
828 const xmlChar *prefix = op->value5;
829 const xmlChar *name = op->value4;
830
831 if (prefix != NULL)
832 fprintf(output, "FUNCTION %s:%s(%d args)",
833 prefix, name, nbargs);
834 else
835 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
836 break;
837 }
838 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
839 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000840 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +0000841#ifdef LIBXML_XPTR_ENABLED
842 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
843#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000844 default:
845 fprintf(output, "UNKNOWN %d\n", op->op); return;
846 }
847 fprintf(output, "\n");
848finish:
849 if (op->ch1 >= 0)
850 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
851 if (op->ch2 >= 0)
852 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
853}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000854
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000855/**
856 * xmlXPathDebugDumpCompExpr:
857 * @output: the FILE * for the output
858 * @comp: the precompiled XPath expression
859 * @depth: the indentation level.
860 *
861 * Dumps the tree of the compiled XPath expression.
862 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000863void
864xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
865 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000866 int i;
867 char shift[100];
868
869 for (i = 0;((i < depth) && (i < 25));i++)
870 shift[2 * i] = shift[2 * i + 1] = ' ';
871 shift[2 * i] = shift[2 * i + 1] = 0;
872
873 fprintf(output, shift);
874
875 if (comp == NULL) {
876 fprintf(output, "Compiled Expression is NULL\n");
877 return;
878 }
879 fprintf(output, "Compiled Expression : %d elements\n",
880 comp->nbStep);
881 i = comp->last;
882 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
883}
Daniel Veillard017b1082001-06-21 11:20:21 +0000884#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000885
886/************************************************************************
887 * *
888 * Parser stacks related functions and macros *
889 * *
890 ************************************************************************/
891
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000892/**
893 * valuePop:
894 * @ctxt: an XPath evaluation context
895 *
896 * Pops the top XPath object from the value stack
897 *
898 * Returns the XPath object just removed
899 */
Daniel Veillard1c732d22002-11-30 11:22:59 +0000900extern xmlXPathObjectPtr
901valuePop(xmlXPathParserContextPtr ctxt)
902{
903 xmlXPathObjectPtr ret;
904
905 if (ctxt->valueNr <= 0)
906 return (0);
907 ctxt->valueNr--;
908 if (ctxt->valueNr > 0)
909 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
910 else
911 ctxt->value = NULL;
912 ret = ctxt->valueTab[ctxt->valueNr];
913 ctxt->valueTab[ctxt->valueNr] = 0;
914 return (ret);
915}
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000916/**
917 * valuePush:
918 * @ctxt: an XPath evaluation context
919 * @value: the XPath object
920 *
921 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000922 *
923 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000924 */
Daniel Veillard1c732d22002-11-30 11:22:59 +0000925extern int
926valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
927{
928 if (ctxt->valueNr >= ctxt->valueMax) {
929 ctxt->valueMax *= 2;
930 ctxt->valueTab =
931 (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
932 ctxt->valueMax *
933 sizeof(ctxt->valueTab[0]));
934 if (ctxt->valueTab == NULL) {
935 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
936 return (0);
937 }
938 }
939 ctxt->valueTab[ctxt->valueNr] = value;
940 ctxt->value = value;
941 return (ctxt->valueNr++);
942}
Owen Taylor3473f882001-02-23 17:55:21 +0000943
Thomas Broyerf06a3d82001-07-16 04:52:57 +0000944/**
945 * xmlXPathPopBoolean:
946 * @ctxt: an XPath parser context
947 *
948 * Pops a boolean from the stack, handling conversion if needed.
949 * Check error with #xmlXPathCheckError.
950 *
951 * Returns the boolean
952 */
953int
954xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
955 xmlXPathObjectPtr obj;
956 int ret;
957
958 obj = valuePop(ctxt);
959 if (obj == NULL) {
960 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
961 return(0);
962 }
963 ret = xmlXPathCastToBoolean(obj);
964 xmlXPathFreeObject(obj);
965 return(ret);
966}
967
968/**
969 * xmlXPathPopNumber:
970 * @ctxt: an XPath parser context
971 *
972 * Pops a number from the stack, handling conversion if needed.
973 * Check error with #xmlXPathCheckError.
974 *
975 * Returns the number
976 */
977double
978xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
979 xmlXPathObjectPtr obj;
980 double ret;
981
982 obj = valuePop(ctxt);
983 if (obj == NULL) {
984 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
985 return(0);
986 }
987 ret = xmlXPathCastToNumber(obj);
988 xmlXPathFreeObject(obj);
989 return(ret);
990}
991
992/**
993 * xmlXPathPopString:
994 * @ctxt: an XPath parser context
995 *
996 * Pops a string from the stack, handling conversion if needed.
997 * Check error with #xmlXPathCheckError.
998 *
999 * Returns the string
1000 */
1001xmlChar *
1002xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
1003 xmlXPathObjectPtr obj;
1004 xmlChar * ret;
1005
1006 obj = valuePop(ctxt);
1007 if (obj == NULL) {
1008 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1009 return(NULL);
1010 }
1011 ret = xmlXPathCastToString(obj);
1012 /* TODO: needs refactoring somewhere else */
1013 if (obj->stringval == ret)
1014 obj->stringval = NULL;
1015 xmlXPathFreeObject(obj);
1016 return(ret);
1017}
1018
1019/**
1020 * xmlXPathPopNodeSet:
1021 * @ctxt: an XPath parser context
1022 *
1023 * Pops a node-set from the stack, handling conversion if needed.
1024 * Check error with #xmlXPathCheckError.
1025 *
1026 * Returns the node-set
1027 */
1028xmlNodeSetPtr
1029xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
1030 xmlXPathObjectPtr obj;
1031 xmlNodeSetPtr ret;
1032
1033 if (ctxt->value == NULL) {
1034 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1035 return(NULL);
1036 }
1037 if (!xmlXPathStackIsNodeSet(ctxt)) {
1038 xmlXPathSetTypeError(ctxt);
1039 return(NULL);
1040 }
1041 obj = valuePop(ctxt);
1042 ret = obj->nodesetval;
Daniel Veillard9deb2422003-07-28 20:40:59 +00001043 /* to fix memory leak of not clearing obj->user */
1044 if (obj->boolval && obj->user != NULL)
1045 xmlFreeNodeList((xmlNodePtr) obj->user);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001046 xmlXPathFreeNodeSetList(obj);
1047 return(ret);
1048}
1049
1050/**
1051 * xmlXPathPopExternal:
1052 * @ctxt: an XPath parser context
1053 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001054 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001055 * Check error with #xmlXPathCheckError.
1056 *
1057 * Returns the object
1058 */
1059void *
1060xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1061 xmlXPathObjectPtr obj;
1062 void * ret;
1063
1064 if (ctxt->value == NULL) {
1065 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1066 return(NULL);
1067 }
1068 if (ctxt->value->type != XPATH_USERS) {
1069 xmlXPathSetTypeError(ctxt);
1070 return(NULL);
1071 }
1072 obj = valuePop(ctxt);
1073 ret = obj->user;
1074 xmlXPathFreeObject(obj);
1075 return(ret);
1076}
1077
Owen Taylor3473f882001-02-23 17:55:21 +00001078/*
1079 * Macros for accessing the content. Those should be used only by the parser,
1080 * and not exported.
1081 *
1082 * Dirty macros, i.e. one need to make assumption on the context to use them
1083 *
1084 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1085 * CUR returns the current xmlChar value, i.e. a 8 bit value
1086 * in ISO-Latin or UTF-8.
1087 * This should be used internally by the parser
1088 * only to compare to ASCII values otherwise it would break when
1089 * running with UTF-8 encoding.
1090 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1091 * to compare on ASCII based substring.
1092 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1093 * strings within the parser.
1094 * CURRENT Returns the current char value, with the full decoding of
1095 * UTF-8 if we are using this mode. It returns an int.
1096 * NEXT Skip to the next character, this does the proper decoding
1097 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1098 * It returns the pointer to the current xmlChar.
1099 */
1100
1101#define CUR (*ctxt->cur)
1102#define SKIP(val) ctxt->cur += (val)
1103#define NXT(val) ctxt->cur[(val)]
1104#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001105#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1106
1107#define COPY_BUF(l,b,i,v) \
1108 if (l == 1) b[i++] = (xmlChar) v; \
1109 else i += xmlCopyChar(l,&b[i],v)
1110
1111#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001112
1113#define SKIP_BLANKS \
1114 while (IS_BLANK(*(ctxt->cur))) NEXT
1115
1116#define CURRENT (*ctxt->cur)
1117#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1118
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001119
1120#ifndef DBL_DIG
1121#define DBL_DIG 16
1122#endif
1123#ifndef DBL_EPSILON
1124#define DBL_EPSILON 1E-9
1125#endif
1126
1127#define UPPER_DOUBLE 1E9
1128#define LOWER_DOUBLE 1E-5
1129
1130#define INTEGER_DIGITS DBL_DIG
1131#define FRACTION_DIGITS (DBL_DIG + 1)
1132#define EXPONENT_DIGITS (3 + 2)
1133
1134/**
1135 * xmlXPathFormatNumber:
1136 * @number: number to format
1137 * @buffer: output buffer
1138 * @buffersize: size of output buffer
1139 *
1140 * Convert the number into a string representation.
1141 */
1142static void
1143xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1144{
Daniel Veillardcda96922001-08-21 10:56:31 +00001145 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001146 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001147 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001148 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001149 break;
1150 case -1:
1151 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001152 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001153 break;
1154 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001155 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001156 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001157 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001158 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001159 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001160 } else if (number == ((int) number)) {
1161 char work[30];
1162 char *ptr, *cur;
1163 int res, value = (int) number;
1164
1165 ptr = &buffer[0];
1166 if (value < 0) {
1167 *ptr++ = '-';
1168 value = -value;
1169 }
1170 if (value == 0) {
1171 *ptr++ = '0';
1172 } else {
1173 cur = &work[0];
1174 while (value != 0) {
1175 res = value % 10;
1176 value = value / 10;
1177 *cur++ = '0' + res;
1178 }
1179 cur--;
1180 while ((cur >= &work[0]) && (ptr - buffer < buffersize)) {
1181 *ptr++ = *cur--;
1182 }
1183 }
1184 if (ptr - buffer < buffersize) {
1185 *ptr = 0;
1186 } else if (buffersize > 0) {
1187 ptr--;
1188 *ptr = 0;
1189 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001190 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001191 /* 3 is sign, decimal point, and terminating zero */
1192 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1193 int integer_place, fraction_place;
1194 char *ptr;
1195 char *after_fraction;
1196 double absolute_value;
1197 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001198
Bjorn Reese70a9da52001-04-21 16:57:29 +00001199 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001200
Bjorn Reese70a9da52001-04-21 16:57:29 +00001201 /*
1202 * First choose format - scientific or regular floating point.
1203 * In either case, result is in work, and after_fraction points
1204 * just past the fractional part.
1205 */
1206 if ( ((absolute_value > UPPER_DOUBLE) ||
1207 (absolute_value < LOWER_DOUBLE)) &&
1208 (absolute_value != 0.0) ) {
1209 /* Use scientific notation */
1210 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1211 fraction_place = DBL_DIG - 1;
1212 snprintf(work, sizeof(work),"%*.*e",
1213 integer_place, fraction_place, number);
1214 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001215 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001216 else {
1217 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001218 if (absolute_value > 0.0)
1219 integer_place = 1 + (int)log10(absolute_value);
1220 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001221 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001222 fraction_place = (integer_place > 0)
1223 ? DBL_DIG - integer_place
1224 : DBL_DIG;
1225 size = snprintf(work, sizeof(work), "%0.*f",
1226 fraction_place, number);
1227 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001228 }
1229
Bjorn Reese70a9da52001-04-21 16:57:29 +00001230 /* Remove fractional trailing zeroes */
1231 ptr = after_fraction;
1232 while (*(--ptr) == '0')
1233 ;
1234 if (*ptr != '.')
1235 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001236 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001237
1238 /* Finally copy result back to caller */
1239 size = strlen(work) + 1;
1240 if (size > buffersize) {
1241 work[buffersize - 1] = 0;
1242 size = buffersize;
1243 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001244 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001245 }
1246 break;
1247 }
1248}
1249
Owen Taylor3473f882001-02-23 17:55:21 +00001250/************************************************************************
1251 * *
1252 * Error handling routines *
1253 * *
1254 ************************************************************************/
1255
1256
Daniel Veillardb44025c2001-10-11 22:55:55 +00001257static const char *xmlXPathErrorMessages[] = {
Owen Taylor3473f882001-02-23 17:55:21 +00001258 "Ok",
1259 "Number encoding",
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001260 "Unfinished literal",
1261 "Start of literal",
Owen Taylor3473f882001-02-23 17:55:21 +00001262 "Expected $ for variable reference",
1263 "Undefined variable",
1264 "Invalid predicate",
1265 "Invalid expression",
1266 "Missing closing curly brace",
1267 "Unregistered function",
1268 "Invalid operand",
1269 "Invalid type",
1270 "Invalid number of arguments",
1271 "Invalid context size",
1272 "Invalid context position",
1273 "Memory allocation error",
1274 "Syntax error",
1275 "Resource error",
1276 "Sub resource error",
Daniel Veillard61d80a22001-04-27 17:13:01 +00001277 "Undefined namespace prefix",
1278 "Encoding error",
1279 "Char out of XML range"
Owen Taylor3473f882001-02-23 17:55:21 +00001280};
1281
1282/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001283 * xmlXPatherror:
Owen Taylor3473f882001-02-23 17:55:21 +00001284 * @ctxt: the XPath Parser context
1285 * @file: the file name
1286 * @line: the line number
1287 * @no: the error number
1288 *
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001289 * Formats an error message.
Owen Taylor3473f882001-02-23 17:55:21 +00001290 */
1291void
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00001292xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
1293 int line ATTRIBUTE_UNUSED, int no) {
Owen Taylor3473f882001-02-23 17:55:21 +00001294 int n;
1295 const xmlChar *cur;
1296 const xmlChar *base;
1297
Owen Taylor3473f882001-02-23 17:55:21 +00001298 cur = ctxt->cur;
1299 base = ctxt->base;
Daniel Veillard118aed72002-09-24 14:13:13 +00001300 if ((cur == NULL) || (base == NULL)) {
1301 if ((ctxt->comp != NULL) && (ctxt->comp->expr != NULL)) {
1302 xmlGenericError(xmlGenericErrorContext,
1303 "XPath error %s in %s\n", xmlXPathErrorMessages[no],
1304 ctxt->comp->expr);
1305 } else {
1306 xmlGenericError(xmlGenericErrorContext,
1307 "XPath error %s\n", xmlXPathErrorMessages[no]);
1308 }
1309
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001310 return;
Daniel Veillard118aed72002-09-24 14:13:13 +00001311 }
1312 xmlGenericError(xmlGenericErrorContext,
1313 "XPath error %s\n", xmlXPathErrorMessages[no]);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001314
Owen Taylor3473f882001-02-23 17:55:21 +00001315 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
1316 cur--;
1317 }
1318 n = 0;
1319 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
1320 cur--;
1321 if ((*cur == '\n') || (*cur == '\r')) cur++;
1322 base = cur;
1323 n = 0;
1324 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
1325 xmlGenericError(xmlGenericErrorContext, "%c", (unsigned char) *cur++);
1326 n++;
1327 }
1328 xmlGenericError(xmlGenericErrorContext, "\n");
1329 cur = ctxt->cur;
1330 while ((*cur == '\n') || (*cur == '\r'))
1331 cur--;
1332 n = 0;
1333 while ((cur != base) && (n++ < 80)) {
1334 xmlGenericError(xmlGenericErrorContext, " ");
1335 base++;
1336 }
1337 xmlGenericError(xmlGenericErrorContext,"^\n");
1338}
1339
1340
1341/************************************************************************
1342 * *
1343 * Routines to handle NodeSets *
1344 * *
1345 ************************************************************************/
1346
1347/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001348 * xmlXPathOrderDocElems:
1349 * @doc: an input document
1350 *
1351 * Call this routine to speed up XPath computation on static documents.
1352 * This stamps all the element nodes with the document order
1353 * Like for line information, the order is kept in the element->content
1354 * field, the value stored is actually - the node number (startting at -1)
1355 * to be able to differenciate from line numbers.
1356 *
1357 * Returns the number of element found in the document or -1 in case
1358 * of error.
1359 */
1360long
1361xmlXPathOrderDocElems(xmlDocPtr doc) {
1362 long count = 0;
1363 xmlNodePtr cur;
1364
1365 if (doc == NULL)
1366 return(-1);
1367 cur = doc->children;
1368 while (cur != NULL) {
1369 if (cur->type == XML_ELEMENT_NODE) {
1370 cur->content = (void *) (-(++count));
1371 if (cur->children != NULL) {
1372 cur = cur->children;
1373 continue;
1374 }
1375 }
1376 if (cur->next != NULL) {
1377 cur = cur->next;
1378 continue;
1379 }
1380 do {
1381 cur = cur->parent;
1382 if (cur == NULL)
1383 break;
1384 if (cur == (xmlNodePtr) doc) {
1385 cur = NULL;
1386 break;
1387 }
1388 if (cur->next != NULL) {
1389 cur = cur->next;
1390 break;
1391 }
1392 } while (cur != NULL);
1393 }
1394 return(count);
1395}
1396
1397/**
Owen Taylor3473f882001-02-23 17:55:21 +00001398 * xmlXPathCmpNodes:
1399 * @node1: the first node
1400 * @node2: the second node
1401 *
1402 * Compare two nodes w.r.t document order
1403 *
1404 * Returns -2 in case of error 1 if first point < second point, 0 if
1405 * that's the same node, -1 otherwise
1406 */
1407int
1408xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1409 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001410 int attr1 = 0, attr2 = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001411 xmlNodePtr cur, root;
1412
1413 if ((node1 == NULL) || (node2 == NULL))
1414 return(-2);
1415 /*
1416 * a couple of optimizations which will avoid computations in most cases
1417 */
Daniel Veillardedfd5882003-03-07 14:20:40 +00001418 if (node1->type == XML_ATTRIBUTE_NODE) {
1419 attr1 = 1;
1420 node1 = node1->parent;
1421 }
1422 if (node2->type == XML_ATTRIBUTE_NODE) {
1423 attr2 = 1;
1424 node2 = node2->parent;
1425 }
1426 if (node1 == node2) {
1427 if (attr1 == attr2)
1428 return(0);
1429 if (attr2 == 1)
1430 return(1);
1431 return(-1);
1432 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00001433 if ((node1->type == XML_NAMESPACE_DECL) ||
1434 (node2->type == XML_NAMESPACE_DECL))
1435 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001436 if (node1 == node2->prev)
1437 return(1);
1438 if (node1 == node2->next)
1439 return(-1);
1440
1441 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001442 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001443 */
1444 if ((node1->type == XML_ELEMENT_NODE) &&
1445 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001446 (0 > (long) node1->content) &&
1447 (0 > (long) node2->content) &&
1448 (node1->doc == node2->doc)) {
1449 long l1, l2;
1450
1451 l1 = -((long) node1->content);
1452 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001453 if (l1 < l2)
1454 return(1);
1455 if (l1 > l2)
1456 return(-1);
1457 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001458
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001459 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001460 * compute depth to root
1461 */
1462 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1463 if (cur == node1)
1464 return(1);
1465 depth2++;
1466 }
1467 root = cur;
1468 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1469 if (cur == node2)
1470 return(-1);
1471 depth1++;
1472 }
1473 /*
1474 * Distinct document (or distinct entities :-( ) case.
1475 */
1476 if (root != cur) {
1477 return(-2);
1478 }
1479 /*
1480 * get the nearest common ancestor.
1481 */
1482 while (depth1 > depth2) {
1483 depth1--;
1484 node1 = node1->parent;
1485 }
1486 while (depth2 > depth1) {
1487 depth2--;
1488 node2 = node2->parent;
1489 }
1490 while (node1->parent != node2->parent) {
1491 node1 = node1->parent;
1492 node2 = node2->parent;
1493 /* should not happen but just in case ... */
1494 if ((node1 == NULL) || (node2 == NULL))
1495 return(-2);
1496 }
1497 /*
1498 * Find who's first.
1499 */
1500 if (node1 == node2->next)
1501 return(-1);
1502 for (cur = node1->next;cur != NULL;cur = cur->next)
1503 if (cur == node2)
1504 return(1);
1505 return(-1); /* assume there is no sibling list corruption */
1506}
1507
1508/**
1509 * xmlXPathNodeSetSort:
1510 * @set: the node set
1511 *
1512 * Sort the node set in document order
1513 */
1514void
1515xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001516 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001517 xmlNodePtr tmp;
1518
1519 if (set == NULL)
1520 return;
1521
1522 /* Use Shell's sort to sort the node-set */
1523 len = set->nodeNr;
1524 for (incr = len / 2; incr > 0; incr /= 2) {
1525 for (i = incr; i < len; i++) {
1526 j = i - incr;
1527 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001528 if (xmlXPathCmpNodes(set->nodeTab[j],
1529 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001530 tmp = set->nodeTab[j];
1531 set->nodeTab[j] = set->nodeTab[j + incr];
1532 set->nodeTab[j + incr] = tmp;
1533 j -= incr;
1534 } else
1535 break;
1536 }
1537 }
1538 }
1539}
1540
1541#define XML_NODESET_DEFAULT 10
1542/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001543 * xmlXPathNodeSetDupNs:
1544 * @node: the parent node of the namespace XPath node
1545 * @ns: the libxml namespace declaration node.
1546 *
1547 * Namespace node in libxml don't match the XPath semantic. In a node set
1548 * the namespace nodes are duplicated and the next pointer is set to the
1549 * parent node in the XPath semantic.
1550 *
1551 * Returns the newly created object.
1552 */
1553static xmlNodePtr
1554xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
1555 xmlNsPtr cur;
1556
1557 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1558 return(NULL);
1559 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
1560 return((xmlNodePtr) ns);
1561
1562 /*
1563 * Allocate a new Namespace and fill the fields.
1564 */
1565 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1566 if (cur == NULL) {
1567 xmlGenericError(xmlGenericErrorContext,
1568 "xmlXPathNodeSetDupNs : malloc failed\n");
1569 return(NULL);
1570 }
1571 memset(cur, 0, sizeof(xmlNs));
1572 cur->type = XML_NAMESPACE_DECL;
1573 if (ns->href != NULL)
1574 cur->href = xmlStrdup(ns->href);
1575 if (ns->prefix != NULL)
1576 cur->prefix = xmlStrdup(ns->prefix);
1577 cur->next = (xmlNsPtr) node;
1578 return((xmlNodePtr) cur);
1579}
1580
1581/**
1582 * xmlXPathNodeSetFreeNs:
1583 * @ns: the XPath namespace node found in a nodeset.
1584 *
1585 * Namespace node in libxml don't match the XPath semantic. In a node set
1586 * the namespace nodes are duplicated and the next pointer is set to the
1587 * parent node in the XPath semantic. Check if such a node need to be freed
1588 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001589void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001590xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
1591 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1592 return;
1593
1594 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
1595 if (ns->href != NULL)
1596 xmlFree((xmlChar *)ns->href);
1597 if (ns->prefix != NULL)
1598 xmlFree((xmlChar *)ns->prefix);
1599 xmlFree(ns);
1600 }
1601}
1602
1603/**
Owen Taylor3473f882001-02-23 17:55:21 +00001604 * xmlXPathNodeSetCreate:
1605 * @val: an initial xmlNodePtr, or NULL
1606 *
1607 * Create a new xmlNodeSetPtr of type double and of value @val
1608 *
1609 * Returns the newly created object.
1610 */
1611xmlNodeSetPtr
1612xmlXPathNodeSetCreate(xmlNodePtr val) {
1613 xmlNodeSetPtr ret;
1614
1615 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1616 if (ret == NULL) {
1617 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001618 "xmlXPathNodeSetCreate: out of memory\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001619 return(NULL);
1620 }
1621 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1622 if (val != NULL) {
1623 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1624 sizeof(xmlNodePtr));
1625 if (ret->nodeTab == NULL) {
1626 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001627 "xmlXPathNodeSetCreate: out of memory\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001628 return(NULL);
1629 }
1630 memset(ret->nodeTab, 0 ,
1631 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1632 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001633 if (val->type == XML_NAMESPACE_DECL) {
1634 xmlNsPtr ns = (xmlNsPtr) val;
1635
1636 ret->nodeTab[ret->nodeNr++] =
1637 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1638 } else
1639 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001640 }
1641 return(ret);
1642}
1643
1644/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001645 * xmlXPathNodeSetContains:
1646 * @cur: the node-set
1647 * @val: the node
1648 *
1649 * checks whether @cur contains @val
1650 *
1651 * Returns true (1) if @cur contains @val, false (0) otherwise
1652 */
1653int
1654xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1655 int i;
1656
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001657 if (val->type == XML_NAMESPACE_DECL) {
1658 for (i = 0; i < cur->nodeNr; i++) {
1659 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1660 xmlNsPtr ns1, ns2;
1661
1662 ns1 = (xmlNsPtr) val;
1663 ns2 = (xmlNsPtr) cur->nodeTab[i];
1664 if (ns1 == ns2)
1665 return(1);
1666 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
1667 (xmlStrEqual(ns1->prefix, ns2->prefix)))
1668 return(1);
1669 }
1670 }
1671 } else {
1672 for (i = 0; i < cur->nodeNr; i++) {
1673 if (cur->nodeTab[i] == val)
1674 return(1);
1675 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001676 }
1677 return(0);
1678}
1679
1680/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001681 * xmlXPathNodeSetAddNs:
1682 * @cur: the initial node set
1683 * @node: the hosting node
1684 * @ns: a the namespace node
1685 *
1686 * add a new namespace node to an existing NodeSet
1687 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00001688void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001689xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
1690 int i;
1691
1692 if ((ns == NULL) || (node == NULL) || (ns->type != XML_NAMESPACE_DECL) ||
1693 (node->type != XML_ELEMENT_NODE))
1694 return;
1695
1696 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1697 /*
1698 * check against doublons
1699 */
1700 for (i = 0;i < cur->nodeNr;i++) {
1701 if ((cur->nodeTab[i] != NULL) &&
1702 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00001703 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001704 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
1705 return;
1706 }
1707
1708 /*
1709 * grow the nodeTab if needed
1710 */
1711 if (cur->nodeMax == 0) {
1712 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1713 sizeof(xmlNodePtr));
1714 if (cur->nodeTab == NULL) {
1715 xmlGenericError(xmlGenericErrorContext,
1716 "xmlXPathNodeSetAdd: out of memory\n");
1717 return;
1718 }
1719 memset(cur->nodeTab, 0 ,
1720 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1721 cur->nodeMax = XML_NODESET_DEFAULT;
1722 } else if (cur->nodeNr == cur->nodeMax) {
1723 xmlNodePtr *temp;
1724
1725 cur->nodeMax *= 2;
1726 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1727 sizeof(xmlNodePtr));
1728 if (temp == NULL) {
1729 xmlGenericError(xmlGenericErrorContext,
1730 "xmlXPathNodeSetAdd: out of memory\n");
1731 return;
1732 }
1733 cur->nodeTab = temp;
1734 }
1735 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
1736}
1737
1738/**
Owen Taylor3473f882001-02-23 17:55:21 +00001739 * xmlXPathNodeSetAdd:
1740 * @cur: the initial node set
1741 * @val: a new xmlNodePtr
1742 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001743 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00001744 */
1745void
1746xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1747 int i;
1748
1749 if (val == NULL) return;
1750
Daniel Veillardef0b4502003-03-24 13:57:34 +00001751#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001752 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1753 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001754#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001755
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001756 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001757 /*
1758 * check against doublons
1759 */
1760 for (i = 0;i < cur->nodeNr;i++)
1761 if (cur->nodeTab[i] == val) return;
1762
1763 /*
1764 * grow the nodeTab if needed
1765 */
1766 if (cur->nodeMax == 0) {
1767 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1768 sizeof(xmlNodePtr));
1769 if (cur->nodeTab == NULL) {
1770 xmlGenericError(xmlGenericErrorContext,
1771 "xmlXPathNodeSetAdd: out of memory\n");
1772 return;
1773 }
1774 memset(cur->nodeTab, 0 ,
1775 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1776 cur->nodeMax = XML_NODESET_DEFAULT;
1777 } else if (cur->nodeNr == cur->nodeMax) {
1778 xmlNodePtr *temp;
1779
1780 cur->nodeMax *= 2;
1781 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1782 sizeof(xmlNodePtr));
1783 if (temp == NULL) {
1784 xmlGenericError(xmlGenericErrorContext,
1785 "xmlXPathNodeSetAdd: out of memory\n");
1786 return;
1787 }
1788 cur->nodeTab = temp;
1789 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001790 if (val->type == XML_NAMESPACE_DECL) {
1791 xmlNsPtr ns = (xmlNsPtr) val;
1792
1793 cur->nodeTab[cur->nodeNr++] =
1794 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1795 } else
1796 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001797}
1798
1799/**
1800 * xmlXPathNodeSetAddUnique:
1801 * @cur: the initial node set
1802 * @val: a new xmlNodePtr
1803 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001804 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00001805 * when we are sure the node is not already in the set.
1806 */
1807void
1808xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1809 if (val == NULL) return;
1810
Daniel Veillardef0b4502003-03-24 13:57:34 +00001811#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001812 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1813 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001814#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001815
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001816 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001817 /*
1818 * grow the nodeTab if needed
1819 */
1820 if (cur->nodeMax == 0) {
1821 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1822 sizeof(xmlNodePtr));
1823 if (cur->nodeTab == NULL) {
1824 xmlGenericError(xmlGenericErrorContext,
1825 "xmlXPathNodeSetAddUnique: out of memory\n");
1826 return;
1827 }
1828 memset(cur->nodeTab, 0 ,
1829 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1830 cur->nodeMax = XML_NODESET_DEFAULT;
1831 } else if (cur->nodeNr == cur->nodeMax) {
1832 xmlNodePtr *temp;
1833
1834 cur->nodeMax *= 2;
1835 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1836 sizeof(xmlNodePtr));
1837 if (temp == NULL) {
1838 xmlGenericError(xmlGenericErrorContext,
1839 "xmlXPathNodeSetAddUnique: out of memory\n");
1840 return;
1841 }
1842 cur->nodeTab = temp;
1843 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001844 if (val->type == XML_NAMESPACE_DECL) {
1845 xmlNsPtr ns = (xmlNsPtr) val;
1846
1847 cur->nodeTab[cur->nodeNr++] =
1848 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1849 } else
1850 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001851}
1852
1853/**
1854 * xmlXPathNodeSetMerge:
1855 * @val1: the first NodeSet or NULL
1856 * @val2: the second NodeSet
1857 *
1858 * Merges two nodesets, all nodes from @val2 are added to @val1
1859 * if @val1 is NULL, a new set is created and copied from @val2
1860 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001861 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00001862 */
1863xmlNodeSetPtr
1864xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001865 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001866
1867 if (val2 == NULL) return(val1);
1868 if (val1 == NULL) {
1869 val1 = xmlXPathNodeSetCreate(NULL);
1870 }
1871
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001872 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001873 initNr = val1->nodeNr;
1874
1875 for (i = 0;i < val2->nodeNr;i++) {
1876 /*
1877 * check against doublons
1878 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001879 skip = 0;
1880 for (j = 0; j < initNr; j++) {
1881 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1882 skip = 1;
1883 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001884 } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) &&
1885 (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) {
1886 xmlNsPtr ns1, ns2;
1887 ns1 = (xmlNsPtr) val1->nodeTab[j];
1888 ns2 = (xmlNsPtr) val2->nodeTab[i];
1889 if ((ns1->next == ns2->next) &&
1890 (xmlStrEqual(ns1->prefix, ns2->prefix))) {
1891 skip = 1;
1892 break;
1893 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001894 }
1895 }
1896 if (skip)
1897 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00001898
1899 /*
1900 * grow the nodeTab if needed
1901 */
1902 if (val1->nodeMax == 0) {
1903 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1904 sizeof(xmlNodePtr));
1905 if (val1->nodeTab == NULL) {
1906 xmlGenericError(xmlGenericErrorContext,
1907 "xmlXPathNodeSetMerge: out of memory\n");
1908 return(NULL);
1909 }
1910 memset(val1->nodeTab, 0 ,
1911 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1912 val1->nodeMax = XML_NODESET_DEFAULT;
1913 } else if (val1->nodeNr == val1->nodeMax) {
1914 xmlNodePtr *temp;
1915
1916 val1->nodeMax *= 2;
1917 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1918 sizeof(xmlNodePtr));
1919 if (temp == NULL) {
1920 xmlGenericError(xmlGenericErrorContext,
1921 "xmlXPathNodeSetMerge: out of memory\n");
1922 return(NULL);
1923 }
1924 val1->nodeTab = temp;
1925 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001926 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1927 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1928
1929 val1->nodeTab[val1->nodeNr++] =
1930 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1931 } else
1932 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00001933 }
1934
1935 return(val1);
1936}
1937
1938/**
Daniel Veillard75be0132002-03-13 10:03:35 +00001939 * xmlXPathNodeSetMergeUnique:
1940 * @val1: the first NodeSet or NULL
1941 * @val2: the second NodeSet
1942 *
1943 * Merges two nodesets, all nodes from @val2 are added to @val1
1944 * if @val1 is NULL, a new set is created and copied from @val2
1945 *
1946 * Returns @val1 once extended or NULL in case of error.
1947 */
1948static xmlNodeSetPtr
1949xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
William M. Brack78637da2003-07-31 14:47:38 +00001950 int i;
Daniel Veillard75be0132002-03-13 10:03:35 +00001951
1952 if (val2 == NULL) return(val1);
1953 if (val1 == NULL) {
1954 val1 = xmlXPathNodeSetCreate(NULL);
1955 }
1956
1957 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Daniel Veillard75be0132002-03-13 10:03:35 +00001958
1959 for (i = 0;i < val2->nodeNr;i++) {
1960 /*
1961 * grow the nodeTab if needed
1962 */
1963 if (val1->nodeMax == 0) {
1964 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1965 sizeof(xmlNodePtr));
1966 if (val1->nodeTab == NULL) {
1967 xmlGenericError(xmlGenericErrorContext,
1968 "xmlXPathNodeSetMerge: out of memory\n");
1969 return(NULL);
1970 }
1971 memset(val1->nodeTab, 0 ,
1972 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1973 val1->nodeMax = XML_NODESET_DEFAULT;
1974 } else if (val1->nodeNr == val1->nodeMax) {
1975 xmlNodePtr *temp;
1976
1977 val1->nodeMax *= 2;
1978 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1979 sizeof(xmlNodePtr));
1980 if (temp == NULL) {
1981 xmlGenericError(xmlGenericErrorContext,
1982 "xmlXPathNodeSetMerge: out of memory\n");
1983 return(NULL);
1984 }
1985 val1->nodeTab = temp;
1986 }
1987 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1988 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1989
1990 val1->nodeTab[val1->nodeNr++] =
1991 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1992 } else
1993 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
1994 }
1995
1996 return(val1);
1997}
1998
1999/**
Owen Taylor3473f882001-02-23 17:55:21 +00002000 * xmlXPathNodeSetDel:
2001 * @cur: the initial node set
2002 * @val: an xmlNodePtr
2003 *
2004 * Removes an xmlNodePtr from an existing NodeSet
2005 */
2006void
2007xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
2008 int i;
2009
2010 if (cur == NULL) return;
2011 if (val == NULL) return;
2012
2013 /*
2014 * check against doublons
2015 */
2016 for (i = 0;i < cur->nodeNr;i++)
2017 if (cur->nodeTab[i] == val) break;
2018
2019 if (i >= cur->nodeNr) {
2020#ifdef DEBUG
2021 xmlGenericError(xmlGenericErrorContext,
2022 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
2023 val->name);
2024#endif
2025 return;
2026 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002027 if ((cur->nodeTab[i] != NULL) &&
2028 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
2029 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002030 cur->nodeNr--;
2031 for (;i < cur->nodeNr;i++)
2032 cur->nodeTab[i] = cur->nodeTab[i + 1];
2033 cur->nodeTab[cur->nodeNr] = NULL;
2034}
2035
2036/**
2037 * xmlXPathNodeSetRemove:
2038 * @cur: the initial node set
2039 * @val: the index to remove
2040 *
2041 * Removes an entry from an existing NodeSet list.
2042 */
2043void
2044xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
2045 if (cur == NULL) return;
2046 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002047 if ((cur->nodeTab[val] != NULL) &&
2048 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
2049 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00002050 cur->nodeNr--;
2051 for (;val < cur->nodeNr;val++)
2052 cur->nodeTab[val] = cur->nodeTab[val + 1];
2053 cur->nodeTab[cur->nodeNr] = NULL;
2054}
2055
2056/**
2057 * xmlXPathFreeNodeSet:
2058 * @obj: the xmlNodeSetPtr to free
2059 *
2060 * Free the NodeSet compound (not the actual nodes !).
2061 */
2062void
2063xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
2064 if (obj == NULL) return;
2065 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002066 int i;
2067
2068 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
2069 for (i = 0;i < obj->nodeNr;i++)
2070 if ((obj->nodeTab[i] != NULL) &&
2071 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
2072 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002073 xmlFree(obj->nodeTab);
2074 }
Owen Taylor3473f882001-02-23 17:55:21 +00002075 xmlFree(obj);
2076}
2077
2078/**
2079 * xmlXPathFreeValueTree:
2080 * @obj: the xmlNodeSetPtr to free
2081 *
2082 * Free the NodeSet compound and the actual tree, this is different
2083 * from xmlXPathFreeNodeSet()
2084 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002085static void
Owen Taylor3473f882001-02-23 17:55:21 +00002086xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
2087 int i;
2088
2089 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002090
2091 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002092 for (i = 0;i < obj->nodeNr;i++) {
2093 if (obj->nodeTab[i] != NULL) {
2094 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2095 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
2096 } else {
2097 xmlFreeNodeList(obj->nodeTab[i]);
2098 }
2099 }
2100 }
Owen Taylor3473f882001-02-23 17:55:21 +00002101 xmlFree(obj->nodeTab);
2102 }
Owen Taylor3473f882001-02-23 17:55:21 +00002103 xmlFree(obj);
2104}
2105
2106#if defined(DEBUG) || defined(DEBUG_STEP)
2107/**
2108 * xmlGenericErrorContextNodeSet:
2109 * @output: a FILE * for the output
2110 * @obj: the xmlNodeSetPtr to free
2111 *
2112 * Quick display of a NodeSet
2113 */
2114void
2115xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
2116 int i;
2117
2118 if (output == NULL) output = xmlGenericErrorContext;
2119 if (obj == NULL) {
2120 fprintf(output, "NodeSet == NULL !\n");
2121 return;
2122 }
2123 if (obj->nodeNr == 0) {
2124 fprintf(output, "NodeSet is empty\n");
2125 return;
2126 }
2127 if (obj->nodeTab == NULL) {
2128 fprintf(output, " nodeTab == NULL !\n");
2129 return;
2130 }
2131 for (i = 0; i < obj->nodeNr; i++) {
2132 if (obj->nodeTab[i] == NULL) {
2133 fprintf(output, " NULL !\n");
2134 return;
2135 }
2136 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
2137 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
2138 fprintf(output, " /");
2139 else if (obj->nodeTab[i]->name == NULL)
2140 fprintf(output, " noname!");
2141 else fprintf(output, " %s", obj->nodeTab[i]->name);
2142 }
2143 fprintf(output, "\n");
2144}
2145#endif
2146
2147/**
2148 * xmlXPathNewNodeSet:
2149 * @val: the NodePtr value
2150 *
2151 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2152 * it with the single Node @val
2153 *
2154 * Returns the newly created object.
2155 */
2156xmlXPathObjectPtr
2157xmlXPathNewNodeSet(xmlNodePtr val) {
2158 xmlXPathObjectPtr ret;
2159
2160 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2161 if (ret == NULL) {
2162 xmlGenericError(xmlGenericErrorContext,
2163 "xmlXPathNewNodeSet: out of memory\n");
2164 return(NULL);
2165 }
2166 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2167 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00002168 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002169 ret->nodesetval = xmlXPathNodeSetCreate(val);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002170 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002171 return(ret);
2172}
2173
2174/**
2175 * xmlXPathNewValueTree:
2176 * @val: the NodePtr value
2177 *
2178 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
2179 * it with the tree root @val
2180 *
2181 * Returns the newly created object.
2182 */
2183xmlXPathObjectPtr
2184xmlXPathNewValueTree(xmlNodePtr val) {
2185 xmlXPathObjectPtr ret;
2186
2187 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2188 if (ret == NULL) {
2189 xmlGenericError(xmlGenericErrorContext,
2190 "xmlXPathNewNodeSet: out of memory\n");
2191 return(NULL);
2192 }
2193 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2194 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002195 ret->boolval = 1;
2196 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00002197 ret->nodesetval = xmlXPathNodeSetCreate(val);
2198 return(ret);
2199}
2200
2201/**
2202 * xmlXPathNewNodeSetList:
2203 * @val: an existing NodeSet
2204 *
2205 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2206 * it with the Nodeset @val
2207 *
2208 * Returns the newly created object.
2209 */
2210xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002211xmlXPathNewNodeSetList(xmlNodeSetPtr val)
2212{
Owen Taylor3473f882001-02-23 17:55:21 +00002213 xmlXPathObjectPtr ret;
2214 int i;
2215
2216 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002217 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002218 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002219 ret = xmlXPathNewNodeSet(NULL);
2220 else {
2221 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
2222 for (i = 1; i < val->nodeNr; ++i)
2223 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2224 }
Owen Taylor3473f882001-02-23 17:55:21 +00002225
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002226 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002227}
2228
2229/**
2230 * xmlXPathWrapNodeSet:
2231 * @val: the NodePtr value
2232 *
2233 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2234 *
2235 * Returns the newly created object.
2236 */
2237xmlXPathObjectPtr
2238xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2239 xmlXPathObjectPtr ret;
2240
2241 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2242 if (ret == NULL) {
2243 xmlGenericError(xmlGenericErrorContext,
2244 "xmlXPathWrapNodeSet: out of memory\n");
2245 return(NULL);
2246 }
2247 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2248 ret->type = XPATH_NODESET;
2249 ret->nodesetval = val;
2250 return(ret);
2251}
2252
2253/**
2254 * xmlXPathFreeNodeSetList:
2255 * @obj: an existing NodeSetList object
2256 *
2257 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2258 * the list contrary to xmlXPathFreeObject().
2259 */
2260void
2261xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2262 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002263 xmlFree(obj);
2264}
2265
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002266/**
2267 * xmlXPathDifference:
2268 * @nodes1: a node-set
2269 * @nodes2: a node-set
2270 *
2271 * Implements the EXSLT - Sets difference() function:
2272 * node-set set:difference (node-set, node-set)
2273 *
2274 * Returns the difference between the two node sets, or nodes1 if
2275 * nodes2 is empty
2276 */
2277xmlNodeSetPtr
2278xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2279 xmlNodeSetPtr ret;
2280 int i, l1;
2281 xmlNodePtr cur;
2282
2283 if (xmlXPathNodeSetIsEmpty(nodes2))
2284 return(nodes1);
2285
2286 ret = xmlXPathNodeSetCreate(NULL);
2287 if (xmlXPathNodeSetIsEmpty(nodes1))
2288 return(ret);
2289
2290 l1 = xmlXPathNodeSetGetLength(nodes1);
2291
2292 for (i = 0; i < l1; i++) {
2293 cur = xmlXPathNodeSetItem(nodes1, i);
2294 if (!xmlXPathNodeSetContains(nodes2, cur))
2295 xmlXPathNodeSetAddUnique(ret, cur);
2296 }
2297 return(ret);
2298}
2299
2300/**
2301 * xmlXPathIntersection:
2302 * @nodes1: a node-set
2303 * @nodes2: a node-set
2304 *
2305 * Implements the EXSLT - Sets intersection() function:
2306 * node-set set:intersection (node-set, node-set)
2307 *
2308 * Returns a node set comprising the nodes that are within both the
2309 * node sets passed as arguments
2310 */
2311xmlNodeSetPtr
2312xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2313 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2314 int i, l1;
2315 xmlNodePtr cur;
2316
2317 if (xmlXPathNodeSetIsEmpty(nodes1))
2318 return(ret);
2319 if (xmlXPathNodeSetIsEmpty(nodes2))
2320 return(ret);
2321
2322 l1 = xmlXPathNodeSetGetLength(nodes1);
2323
2324 for (i = 0; i < l1; i++) {
2325 cur = xmlXPathNodeSetItem(nodes1, i);
2326 if (xmlXPathNodeSetContains(nodes2, cur))
2327 xmlXPathNodeSetAddUnique(ret, cur);
2328 }
2329 return(ret);
2330}
2331
2332/**
2333 * xmlXPathDistinctSorted:
2334 * @nodes: a node-set, sorted by document order
2335 *
2336 * Implements the EXSLT - Sets distinct() function:
2337 * node-set set:distinct (node-set)
2338 *
2339 * Returns a subset of the nodes contained in @nodes, or @nodes if
2340 * it is empty
2341 */
2342xmlNodeSetPtr
2343xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2344 xmlNodeSetPtr ret;
2345 xmlHashTablePtr hash;
2346 int i, l;
2347 xmlChar * strval;
2348 xmlNodePtr cur;
2349
2350 if (xmlXPathNodeSetIsEmpty(nodes))
2351 return(nodes);
2352
2353 ret = xmlXPathNodeSetCreate(NULL);
2354 l = xmlXPathNodeSetGetLength(nodes);
2355 hash = xmlHashCreate (l);
2356 for (i = 0; i < l; i++) {
2357 cur = xmlXPathNodeSetItem(nodes, i);
2358 strval = xmlXPathCastNodeToString(cur);
2359 if (xmlHashLookup(hash, strval) == NULL) {
2360 xmlHashAddEntry(hash, strval, strval);
2361 xmlXPathNodeSetAddUnique(ret, cur);
2362 } else {
2363 xmlFree(strval);
2364 }
2365 }
2366 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2367 return(ret);
2368}
2369
2370/**
2371 * xmlXPathDistinct:
2372 * @nodes: a node-set
2373 *
2374 * Implements the EXSLT - Sets distinct() function:
2375 * node-set set:distinct (node-set)
2376 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2377 * is called with the sorted node-set
2378 *
2379 * Returns a subset of the nodes contained in @nodes, or @nodes if
2380 * it is empty
2381 */
2382xmlNodeSetPtr
2383xmlXPathDistinct (xmlNodeSetPtr nodes) {
2384 if (xmlXPathNodeSetIsEmpty(nodes))
2385 return(nodes);
2386
2387 xmlXPathNodeSetSort(nodes);
2388 return(xmlXPathDistinctSorted(nodes));
2389}
2390
2391/**
2392 * xmlXPathHasSameNodes:
2393 * @nodes1: a node-set
2394 * @nodes2: a node-set
2395 *
2396 * Implements the EXSLT - Sets has-same-nodes function:
2397 * boolean set:has-same-node(node-set, node-set)
2398 *
2399 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2400 * otherwise
2401 */
2402int
2403xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2404 int i, l;
2405 xmlNodePtr cur;
2406
2407 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2408 xmlXPathNodeSetIsEmpty(nodes2))
2409 return(0);
2410
2411 l = xmlXPathNodeSetGetLength(nodes1);
2412 for (i = 0; i < l; i++) {
2413 cur = xmlXPathNodeSetItem(nodes1, i);
2414 if (xmlXPathNodeSetContains(nodes2, cur))
2415 return(1);
2416 }
2417 return(0);
2418}
2419
2420/**
2421 * xmlXPathNodeLeadingSorted:
2422 * @nodes: a node-set, sorted by document order
2423 * @node: a node
2424 *
2425 * Implements the EXSLT - Sets leading() function:
2426 * node-set set:leading (node-set, node-set)
2427 *
2428 * Returns the nodes in @nodes that precede @node in document order,
2429 * @nodes if @node is NULL or an empty node-set if @nodes
2430 * doesn't contain @node
2431 */
2432xmlNodeSetPtr
2433xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2434 int i, l;
2435 xmlNodePtr cur;
2436 xmlNodeSetPtr ret;
2437
2438 if (node == NULL)
2439 return(nodes);
2440
2441 ret = xmlXPathNodeSetCreate(NULL);
2442 if (xmlXPathNodeSetIsEmpty(nodes) ||
2443 (!xmlXPathNodeSetContains(nodes, node)))
2444 return(ret);
2445
2446 l = xmlXPathNodeSetGetLength(nodes);
2447 for (i = 0; i < l; i++) {
2448 cur = xmlXPathNodeSetItem(nodes, i);
2449 if (cur == node)
2450 break;
2451 xmlXPathNodeSetAddUnique(ret, cur);
2452 }
2453 return(ret);
2454}
2455
2456/**
2457 * xmlXPathNodeLeading:
2458 * @nodes: a node-set
2459 * @node: a node
2460 *
2461 * Implements the EXSLT - Sets leading() function:
2462 * node-set set:leading (node-set, node-set)
2463 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2464 * is called.
2465 *
2466 * Returns the nodes in @nodes that precede @node in document order,
2467 * @nodes if @node is NULL or an empty node-set if @nodes
2468 * doesn't contain @node
2469 */
2470xmlNodeSetPtr
2471xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2472 xmlXPathNodeSetSort(nodes);
2473 return(xmlXPathNodeLeadingSorted(nodes, node));
2474}
2475
2476/**
2477 * xmlXPathLeadingSorted:
2478 * @nodes1: a node-set, sorted by document order
2479 * @nodes2: a node-set, sorted by document order
2480 *
2481 * Implements the EXSLT - Sets leading() function:
2482 * node-set set:leading (node-set, node-set)
2483 *
2484 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2485 * in document order, @nodes1 if @nodes2 is NULL or empty or
2486 * an empty node-set if @nodes1 doesn't contain @nodes2
2487 */
2488xmlNodeSetPtr
2489xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2490 if (xmlXPathNodeSetIsEmpty(nodes2))
2491 return(nodes1);
2492 return(xmlXPathNodeLeadingSorted(nodes1,
2493 xmlXPathNodeSetItem(nodes2, 1)));
2494}
2495
2496/**
2497 * xmlXPathLeading:
2498 * @nodes1: a node-set
2499 * @nodes2: a node-set
2500 *
2501 * Implements the EXSLT - Sets leading() function:
2502 * node-set set:leading (node-set, node-set)
2503 * @nodes1 and @nodes2 are sorted by document order, then
2504 * #exslSetsLeadingSorted is called.
2505 *
2506 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2507 * in document order, @nodes1 if @nodes2 is NULL or empty or
2508 * an empty node-set if @nodes1 doesn't contain @nodes2
2509 */
2510xmlNodeSetPtr
2511xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2512 if (xmlXPathNodeSetIsEmpty(nodes2))
2513 return(nodes1);
2514 if (xmlXPathNodeSetIsEmpty(nodes1))
2515 return(xmlXPathNodeSetCreate(NULL));
2516 xmlXPathNodeSetSort(nodes1);
2517 xmlXPathNodeSetSort(nodes2);
2518 return(xmlXPathNodeLeadingSorted(nodes1,
2519 xmlXPathNodeSetItem(nodes2, 1)));
2520}
2521
2522/**
2523 * xmlXPathNodeTrailingSorted:
2524 * @nodes: a node-set, sorted by document order
2525 * @node: a node
2526 *
2527 * Implements the EXSLT - Sets trailing() function:
2528 * node-set set:trailing (node-set, node-set)
2529 *
2530 * Returns the nodes in @nodes that follow @node in document order,
2531 * @nodes if @node is NULL or an empty node-set if @nodes
2532 * doesn't contain @node
2533 */
2534xmlNodeSetPtr
2535xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2536 int i, l;
2537 xmlNodePtr cur;
2538 xmlNodeSetPtr ret;
2539
2540 if (node == NULL)
2541 return(nodes);
2542
2543 ret = xmlXPathNodeSetCreate(NULL);
2544 if (xmlXPathNodeSetIsEmpty(nodes) ||
2545 (!xmlXPathNodeSetContains(nodes, node)))
2546 return(ret);
2547
2548 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002549 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002550 cur = xmlXPathNodeSetItem(nodes, i);
2551 if (cur == node)
2552 break;
2553 xmlXPathNodeSetAddUnique(ret, cur);
2554 }
2555 return(ret);
2556}
2557
2558/**
2559 * xmlXPathNodeTrailing:
2560 * @nodes: a node-set
2561 * @node: a node
2562 *
2563 * Implements the EXSLT - Sets trailing() function:
2564 * node-set set:trailing (node-set, node-set)
2565 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2566 * is called.
2567 *
2568 * Returns the nodes in @nodes that follow @node in document order,
2569 * @nodes if @node is NULL or an empty node-set if @nodes
2570 * doesn't contain @node
2571 */
2572xmlNodeSetPtr
2573xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2574 xmlXPathNodeSetSort(nodes);
2575 return(xmlXPathNodeTrailingSorted(nodes, node));
2576}
2577
2578/**
2579 * xmlXPathTrailingSorted:
2580 * @nodes1: a node-set, sorted by document order
2581 * @nodes2: a node-set, sorted by document order
2582 *
2583 * Implements the EXSLT - Sets trailing() function:
2584 * node-set set:trailing (node-set, node-set)
2585 *
2586 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2587 * in document order, @nodes1 if @nodes2 is NULL or empty or
2588 * an empty node-set if @nodes1 doesn't contain @nodes2
2589 */
2590xmlNodeSetPtr
2591xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2592 if (xmlXPathNodeSetIsEmpty(nodes2))
2593 return(nodes1);
2594 return(xmlXPathNodeTrailingSorted(nodes1,
2595 xmlXPathNodeSetItem(nodes2, 0)));
2596}
2597
2598/**
2599 * xmlXPathTrailing:
2600 * @nodes1: a node-set
2601 * @nodes2: a node-set
2602 *
2603 * Implements the EXSLT - Sets trailing() function:
2604 * node-set set:trailing (node-set, node-set)
2605 * @nodes1 and @nodes2 are sorted by document order, then
2606 * #xmlXPathTrailingSorted is called.
2607 *
2608 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2609 * in document order, @nodes1 if @nodes2 is NULL or empty or
2610 * an empty node-set if @nodes1 doesn't contain @nodes2
2611 */
2612xmlNodeSetPtr
2613xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2614 if (xmlXPathNodeSetIsEmpty(nodes2))
2615 return(nodes1);
2616 if (xmlXPathNodeSetIsEmpty(nodes1))
2617 return(xmlXPathNodeSetCreate(NULL));
2618 xmlXPathNodeSetSort(nodes1);
2619 xmlXPathNodeSetSort(nodes2);
2620 return(xmlXPathNodeTrailingSorted(nodes1,
2621 xmlXPathNodeSetItem(nodes2, 0)));
2622}
2623
Owen Taylor3473f882001-02-23 17:55:21 +00002624/************************************************************************
2625 * *
2626 * Routines to handle extra functions *
2627 * *
2628 ************************************************************************/
2629
2630/**
2631 * xmlXPathRegisterFunc:
2632 * @ctxt: the XPath context
2633 * @name: the function name
2634 * @f: the function implementation or NULL
2635 *
2636 * Register a new function. If @f is NULL it unregisters the function
2637 *
2638 * Returns 0 in case of success, -1 in case of error
2639 */
2640int
2641xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2642 xmlXPathFunction f) {
2643 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2644}
2645
2646/**
2647 * xmlXPathRegisterFuncNS:
2648 * @ctxt: the XPath context
2649 * @name: the function name
2650 * @ns_uri: the function namespace URI
2651 * @f: the function implementation or NULL
2652 *
2653 * Register a new function. If @f is NULL it unregisters the function
2654 *
2655 * Returns 0 in case of success, -1 in case of error
2656 */
2657int
2658xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2659 const xmlChar *ns_uri, xmlXPathFunction f) {
2660 if (ctxt == NULL)
2661 return(-1);
2662 if (name == NULL)
2663 return(-1);
2664
2665 if (ctxt->funcHash == NULL)
2666 ctxt->funcHash = xmlHashCreate(0);
2667 if (ctxt->funcHash == NULL)
2668 return(-1);
2669 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2670}
2671
2672/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002673 * xmlXPathRegisterFuncLookup:
2674 * @ctxt: the XPath context
2675 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002676 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00002677 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002678 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00002679 */
2680void
2681xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2682 xmlXPathFuncLookupFunc f,
2683 void *funcCtxt) {
2684 if (ctxt == NULL)
2685 return;
2686 ctxt->funcLookupFunc = (void *) f;
2687 ctxt->funcLookupData = funcCtxt;
2688}
2689
2690/**
Owen Taylor3473f882001-02-23 17:55:21 +00002691 * xmlXPathFunctionLookup:
2692 * @ctxt: the XPath context
2693 * @name: the function name
2694 *
2695 * Search in the Function array of the context for the given
2696 * function.
2697 *
2698 * Returns the xmlXPathFunction or NULL if not found
2699 */
2700xmlXPathFunction
2701xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002702 if (ctxt == NULL)
2703 return (NULL);
2704
2705 if (ctxt->funcLookupFunc != NULL) {
2706 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002707 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002708
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002709 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002710 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002711 if (ret != NULL)
2712 return(ret);
2713 }
Owen Taylor3473f882001-02-23 17:55:21 +00002714 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2715}
2716
2717/**
2718 * xmlXPathFunctionLookupNS:
2719 * @ctxt: the XPath context
2720 * @name: the function name
2721 * @ns_uri: the function namespace URI
2722 *
2723 * Search in the Function array of the context for the given
2724 * function.
2725 *
2726 * Returns the xmlXPathFunction or NULL if not found
2727 */
2728xmlXPathFunction
2729xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2730 const xmlChar *ns_uri) {
2731 if (ctxt == NULL)
2732 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002733 if (name == NULL)
2734 return(NULL);
2735
Thomas Broyerba4ad322001-07-26 16:55:21 +00002736 if (ctxt->funcLookupFunc != NULL) {
2737 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002738 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002739
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002740 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002741 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002742 if (ret != NULL)
2743 return(ret);
2744 }
2745
2746 if (ctxt->funcHash == NULL)
2747 return(NULL);
2748
Owen Taylor3473f882001-02-23 17:55:21 +00002749 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2750}
2751
2752/**
2753 * xmlXPathRegisteredFuncsCleanup:
2754 * @ctxt: the XPath context
2755 *
2756 * Cleanup the XPath context data associated to registered functions
2757 */
2758void
2759xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2760 if (ctxt == NULL)
2761 return;
2762
2763 xmlHashFree(ctxt->funcHash, NULL);
2764 ctxt->funcHash = NULL;
2765}
2766
2767/************************************************************************
2768 * *
2769 * Routines to handle Variable *
2770 * *
2771 ************************************************************************/
2772
2773/**
2774 * xmlXPathRegisterVariable:
2775 * @ctxt: the XPath context
2776 * @name: the variable name
2777 * @value: the variable value or NULL
2778 *
2779 * Register a new variable value. If @value is NULL it unregisters
2780 * the variable
2781 *
2782 * Returns 0 in case of success, -1 in case of error
2783 */
2784int
2785xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2786 xmlXPathObjectPtr value) {
2787 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2788}
2789
2790/**
2791 * xmlXPathRegisterVariableNS:
2792 * @ctxt: the XPath context
2793 * @name: the variable name
2794 * @ns_uri: the variable namespace URI
2795 * @value: the variable value or NULL
2796 *
2797 * Register a new variable value. If @value is NULL it unregisters
2798 * the variable
2799 *
2800 * Returns 0 in case of success, -1 in case of error
2801 */
2802int
2803xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2804 const xmlChar *ns_uri,
2805 xmlXPathObjectPtr value) {
2806 if (ctxt == NULL)
2807 return(-1);
2808 if (name == NULL)
2809 return(-1);
2810
2811 if (ctxt->varHash == NULL)
2812 ctxt->varHash = xmlHashCreate(0);
2813 if (ctxt->varHash == NULL)
2814 return(-1);
2815 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2816 (void *) value,
2817 (xmlHashDeallocator)xmlXPathFreeObject));
2818}
2819
2820/**
2821 * xmlXPathRegisterVariableLookup:
2822 * @ctxt: the XPath context
2823 * @f: the lookup function
2824 * @data: the lookup data
2825 *
2826 * register an external mechanism to do variable lookup
2827 */
2828void
2829xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2830 xmlXPathVariableLookupFunc f, void *data) {
2831 if (ctxt == NULL)
2832 return;
2833 ctxt->varLookupFunc = (void *) f;
2834 ctxt->varLookupData = data;
2835}
2836
2837/**
2838 * xmlXPathVariableLookup:
2839 * @ctxt: the XPath context
2840 * @name: the variable name
2841 *
2842 * Search in the Variable array of the context for the given
2843 * variable value.
2844 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002845 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002846 */
2847xmlXPathObjectPtr
2848xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2849 if (ctxt == NULL)
2850 return(NULL);
2851
2852 if (ctxt->varLookupFunc != NULL) {
2853 xmlXPathObjectPtr ret;
2854
2855 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2856 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00002857 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002858 }
2859 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
2860}
2861
2862/**
2863 * xmlXPathVariableLookupNS:
2864 * @ctxt: the XPath context
2865 * @name: the variable name
2866 * @ns_uri: the variable namespace URI
2867 *
2868 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00002869 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00002870 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002871 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002872 */
2873xmlXPathObjectPtr
2874xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2875 const xmlChar *ns_uri) {
2876 if (ctxt == NULL)
2877 return(NULL);
2878
2879 if (ctxt->varLookupFunc != NULL) {
2880 xmlXPathObjectPtr ret;
2881
2882 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2883 (ctxt->varLookupData, name, ns_uri);
2884 if (ret != NULL) return(ret);
2885 }
2886
2887 if (ctxt->varHash == NULL)
2888 return(NULL);
2889 if (name == NULL)
2890 return(NULL);
2891
Daniel Veillard8c357d52001-07-03 23:43:33 +00002892 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
2893 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00002894}
2895
2896/**
2897 * xmlXPathRegisteredVariablesCleanup:
2898 * @ctxt: the XPath context
2899 *
2900 * Cleanup the XPath context data associated to registered variables
2901 */
2902void
2903xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
2904 if (ctxt == NULL)
2905 return;
2906
Daniel Veillard76d66f42001-05-16 21:05:17 +00002907 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00002908 ctxt->varHash = NULL;
2909}
2910
2911/**
2912 * xmlXPathRegisterNs:
2913 * @ctxt: the XPath context
2914 * @prefix: the namespace prefix
2915 * @ns_uri: the namespace name
2916 *
2917 * Register a new namespace. If @ns_uri is NULL it unregisters
2918 * the namespace
2919 *
2920 * Returns 0 in case of success, -1 in case of error
2921 */
2922int
2923xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
2924 const xmlChar *ns_uri) {
2925 if (ctxt == NULL)
2926 return(-1);
2927 if (prefix == NULL)
2928 return(-1);
2929
2930 if (ctxt->nsHash == NULL)
2931 ctxt->nsHash = xmlHashCreate(10);
2932 if (ctxt->nsHash == NULL)
2933 return(-1);
Daniel Veillard42766c02002-08-22 20:52:17 +00002934 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00002935 (xmlHashDeallocator)xmlFree));
2936}
2937
2938/**
2939 * xmlXPathNsLookup:
2940 * @ctxt: the XPath context
2941 * @prefix: the namespace prefix value
2942 *
2943 * Search in the namespace declaration array of the context for the given
2944 * namespace name associated to the given prefix
2945 *
2946 * Returns the value or NULL if not found
2947 */
2948const xmlChar *
2949xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
2950 if (ctxt == NULL)
2951 return(NULL);
2952 if (prefix == NULL)
2953 return(NULL);
2954
2955#ifdef XML_XML_NAMESPACE
2956 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
2957 return(XML_XML_NAMESPACE);
2958#endif
2959
Daniel Veillardc8f620b2001-04-30 20:31:33 +00002960 if (ctxt->namespaces != NULL) {
2961 int i;
2962
2963 for (i = 0;i < ctxt->nsNr;i++) {
2964 if ((ctxt->namespaces[i] != NULL) &&
2965 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
2966 return(ctxt->namespaces[i]->href);
2967 }
2968 }
Owen Taylor3473f882001-02-23 17:55:21 +00002969
2970 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
2971}
2972
2973/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002974 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00002975 * @ctxt: the XPath context
2976 *
2977 * Cleanup the XPath context data associated to registered variables
2978 */
2979void
2980xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
2981 if (ctxt == NULL)
2982 return;
2983
Daniel Veillard42766c02002-08-22 20:52:17 +00002984 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00002985 ctxt->nsHash = NULL;
2986}
2987
2988/************************************************************************
2989 * *
2990 * Routines to handle Values *
2991 * *
2992 ************************************************************************/
2993
2994/* Allocations are terrible, one need to optimize all this !!! */
2995
2996/**
2997 * xmlXPathNewFloat:
2998 * @val: the double value
2999 *
3000 * Create a new xmlXPathObjectPtr of type double and of value @val
3001 *
3002 * Returns the newly created object.
3003 */
3004xmlXPathObjectPtr
3005xmlXPathNewFloat(double val) {
3006 xmlXPathObjectPtr ret;
3007
3008 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3009 if (ret == NULL) {
3010 xmlGenericError(xmlGenericErrorContext,
3011 "xmlXPathNewFloat: out of memory\n");
3012 return(NULL);
3013 }
3014 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3015 ret->type = XPATH_NUMBER;
3016 ret->floatval = val;
3017 return(ret);
3018}
3019
3020/**
3021 * xmlXPathNewBoolean:
3022 * @val: the boolean value
3023 *
3024 * Create a new xmlXPathObjectPtr of type boolean and of value @val
3025 *
3026 * Returns the newly created object.
3027 */
3028xmlXPathObjectPtr
3029xmlXPathNewBoolean(int val) {
3030 xmlXPathObjectPtr ret;
3031
3032 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3033 if (ret == NULL) {
3034 xmlGenericError(xmlGenericErrorContext,
3035 "xmlXPathNewBoolean: out of memory\n");
3036 return(NULL);
3037 }
3038 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3039 ret->type = XPATH_BOOLEAN;
3040 ret->boolval = (val != 0);
3041 return(ret);
3042}
3043
3044/**
3045 * xmlXPathNewString:
3046 * @val: the xmlChar * value
3047 *
3048 * Create a new xmlXPathObjectPtr of type string and of value @val
3049 *
3050 * Returns the newly created object.
3051 */
3052xmlXPathObjectPtr
3053xmlXPathNewString(const xmlChar *val) {
3054 xmlXPathObjectPtr ret;
3055
3056 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3057 if (ret == NULL) {
3058 xmlGenericError(xmlGenericErrorContext,
3059 "xmlXPathNewString: out of memory\n");
3060 return(NULL);
3061 }
3062 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3063 ret->type = XPATH_STRING;
3064 if (val != NULL)
3065 ret->stringval = xmlStrdup(val);
3066 else
3067 ret->stringval = xmlStrdup((const xmlChar *)"");
3068 return(ret);
3069}
3070
3071/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003072 * xmlXPathWrapString:
3073 * @val: the xmlChar * value
3074 *
3075 * Wraps the @val string into an XPath object.
3076 *
3077 * Returns the newly created object.
3078 */
3079xmlXPathObjectPtr
3080xmlXPathWrapString (xmlChar *val) {
3081 xmlXPathObjectPtr ret;
3082
3083 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3084 if (ret == NULL) {
3085 xmlGenericError(xmlGenericErrorContext,
3086 "xmlXPathWrapString: out of memory\n");
3087 return(NULL);
3088 }
3089 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3090 ret->type = XPATH_STRING;
3091 ret->stringval = val;
3092 return(ret);
3093}
3094
3095/**
Owen Taylor3473f882001-02-23 17:55:21 +00003096 * xmlXPathNewCString:
3097 * @val: the char * value
3098 *
3099 * Create a new xmlXPathObjectPtr of type string and of value @val
3100 *
3101 * Returns the newly created object.
3102 */
3103xmlXPathObjectPtr
3104xmlXPathNewCString(const char *val) {
3105 xmlXPathObjectPtr ret;
3106
3107 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3108 if (ret == NULL) {
3109 xmlGenericError(xmlGenericErrorContext,
3110 "xmlXPathNewCString: out of memory\n");
3111 return(NULL);
3112 }
3113 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3114 ret->type = XPATH_STRING;
3115 ret->stringval = xmlStrdup(BAD_CAST val);
3116 return(ret);
3117}
3118
3119/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003120 * xmlXPathWrapCString:
3121 * @val: the char * value
3122 *
3123 * Wraps a string into an XPath object.
3124 *
3125 * Returns the newly created object.
3126 */
3127xmlXPathObjectPtr
3128xmlXPathWrapCString (char * val) {
3129 return(xmlXPathWrapString((xmlChar *)(val)));
3130}
3131
3132/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003133 * xmlXPathWrapExternal:
3134 * @val: the user data
3135 *
3136 * Wraps the @val data into an XPath object.
3137 *
3138 * Returns the newly created object.
3139 */
3140xmlXPathObjectPtr
3141xmlXPathWrapExternal (void *val) {
3142 xmlXPathObjectPtr ret;
3143
3144 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3145 if (ret == NULL) {
3146 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003147 "xmlXPathWrapExternal: out of memory\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003148 return(NULL);
3149 }
3150 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3151 ret->type = XPATH_USERS;
3152 ret->user = val;
3153 return(ret);
3154}
3155
3156/**
Owen Taylor3473f882001-02-23 17:55:21 +00003157 * xmlXPathObjectCopy:
3158 * @val: the original object
3159 *
3160 * allocate a new copy of a given object
3161 *
3162 * Returns the newly created object.
3163 */
3164xmlXPathObjectPtr
3165xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3166 xmlXPathObjectPtr ret;
3167
3168 if (val == NULL)
3169 return(NULL);
3170
3171 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3172 if (ret == NULL) {
3173 xmlGenericError(xmlGenericErrorContext,
3174 "xmlXPathObjectCopy: out of memory\n");
3175 return(NULL);
3176 }
3177 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3178 switch (val->type) {
3179 case XPATH_BOOLEAN:
3180 case XPATH_NUMBER:
3181 case XPATH_POINT:
3182 case XPATH_RANGE:
3183 break;
3184 case XPATH_STRING:
3185 ret->stringval = xmlStrdup(val->stringval);
3186 break;
3187 case XPATH_XSLT_TREE:
3188 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003189 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003190 xmlNodePtr cur, tmp;
3191 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003192
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003193 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00003194 top = xmlNewDoc(NULL);
3195 top->name = (char *)
3196 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003197 ret->user = top;
3198 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003199 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003200 cur = val->nodesetval->nodeTab[0]->children;
3201 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003202 tmp = xmlDocCopyNode(cur, top, 1);
3203 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003204 cur = cur->next;
3205 }
3206 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003207 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003208 } else
Owen Taylor3473f882001-02-23 17:55:21 +00003209 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003210 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00003211 break;
3212 case XPATH_NODESET:
3213 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003214 /* Do not deallocate the copied tree value */
3215 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003216 break;
3217 case XPATH_LOCATIONSET:
3218#ifdef LIBXML_XPTR_ENABLED
3219 {
3220 xmlLocationSetPtr loc = val->user;
3221 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3222 break;
3223 }
3224#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00003225 case XPATH_USERS:
3226 ret->user = val->user;
3227 break;
3228 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00003229 xmlGenericError(xmlGenericErrorContext,
3230 "xmlXPathObjectCopy: unsupported type %d\n",
3231 val->type);
3232 break;
3233 }
3234 return(ret);
3235}
3236
3237/**
3238 * xmlXPathFreeObject:
3239 * @obj: the object to free
3240 *
3241 * Free up an xmlXPathObjectPtr object.
3242 */
3243void
3244xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3245 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003246 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00003247 if (obj->boolval) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003248 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003249 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00003250 xmlFreeNodeList((xmlNodePtr) obj->user);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003251 } else if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00003252 xmlXPathFreeValueTree(obj->nodesetval);
3253 } else {
3254 if (obj->nodesetval != NULL)
3255 xmlXPathFreeNodeSet(obj->nodesetval);
3256 }
Owen Taylor3473f882001-02-23 17:55:21 +00003257#ifdef LIBXML_XPTR_ENABLED
3258 } else if (obj->type == XPATH_LOCATIONSET) {
3259 if (obj->user != NULL)
3260 xmlXPtrFreeLocationSet(obj->user);
3261#endif
3262 } else if (obj->type == XPATH_STRING) {
3263 if (obj->stringval != NULL)
3264 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00003265 }
3266
Owen Taylor3473f882001-02-23 17:55:21 +00003267 xmlFree(obj);
3268}
3269
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003270
3271/************************************************************************
3272 * *
3273 * Type Casting Routines *
3274 * *
3275 ************************************************************************/
3276
3277/**
3278 * xmlXPathCastBooleanToString:
3279 * @val: a boolean
3280 *
3281 * Converts a boolean to its string value.
3282 *
3283 * Returns a newly allocated string.
3284 */
3285xmlChar *
3286xmlXPathCastBooleanToString (int val) {
3287 xmlChar *ret;
3288 if (val)
3289 ret = xmlStrdup((const xmlChar *) "true");
3290 else
3291 ret = xmlStrdup((const xmlChar *) "false");
3292 return(ret);
3293}
3294
3295/**
3296 * xmlXPathCastNumberToString:
3297 * @val: a number
3298 *
3299 * Converts a number to its string value.
3300 *
3301 * Returns a newly allocated string.
3302 */
3303xmlChar *
3304xmlXPathCastNumberToString (double val) {
3305 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00003306 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003307 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003308 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003309 break;
3310 case -1:
3311 ret = xmlStrdup((const xmlChar *) "-Infinity");
3312 break;
3313 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003314 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003315 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00003316 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
3317 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003318 } else {
3319 /* could be improved */
3320 char buf[100];
3321 xmlXPathFormatNumber(val, buf, 100);
3322 ret = xmlStrdup((const xmlChar *) buf);
3323 }
3324 }
3325 return(ret);
3326}
3327
3328/**
3329 * xmlXPathCastNodeToString:
3330 * @node: a node
3331 *
3332 * Converts a node to its string value.
3333 *
3334 * Returns a newly allocated string.
3335 */
3336xmlChar *
3337xmlXPathCastNodeToString (xmlNodePtr node) {
3338 return(xmlNodeGetContent(node));
3339}
3340
3341/**
3342 * xmlXPathCastNodeSetToString:
3343 * @ns: a node-set
3344 *
3345 * Converts a node-set to its string value.
3346 *
3347 * Returns a newly allocated string.
3348 */
3349xmlChar *
3350xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3351 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3352 return(xmlStrdup((const xmlChar *) ""));
3353
3354 xmlXPathNodeSetSort(ns);
3355 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3356}
3357
3358/**
3359 * xmlXPathCastToString:
3360 * @val: an XPath object
3361 *
3362 * Converts an existing object to its string() equivalent
3363 *
3364 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003365 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003366 * string object).
3367 */
3368xmlChar *
3369xmlXPathCastToString(xmlXPathObjectPtr val) {
3370 xmlChar *ret = NULL;
3371
3372 if (val == NULL)
3373 return(xmlStrdup((const xmlChar *) ""));
3374 switch (val->type) {
3375 case XPATH_UNDEFINED:
3376#ifdef DEBUG_EXPR
3377 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3378#endif
3379 ret = xmlStrdup((const xmlChar *) "");
3380 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003381 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003382 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003383 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3384 break;
3385 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00003386 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003387 case XPATH_BOOLEAN:
3388 ret = xmlXPathCastBooleanToString(val->boolval);
3389 break;
3390 case XPATH_NUMBER: {
3391 ret = xmlXPathCastNumberToString(val->floatval);
3392 break;
3393 }
3394 case XPATH_USERS:
3395 case XPATH_POINT:
3396 case XPATH_RANGE:
3397 case XPATH_LOCATIONSET:
3398 TODO
3399 ret = xmlStrdup((const xmlChar *) "");
3400 break;
3401 }
3402 return(ret);
3403}
3404
3405/**
3406 * xmlXPathConvertString:
3407 * @val: an XPath object
3408 *
3409 * Converts an existing object to its string() equivalent
3410 *
3411 * Returns the new object, the old one is freed (or the operation
3412 * is done directly on @val)
3413 */
3414xmlXPathObjectPtr
3415xmlXPathConvertString(xmlXPathObjectPtr val) {
3416 xmlChar *res = NULL;
3417
3418 if (val == NULL)
3419 return(xmlXPathNewCString(""));
3420
3421 switch (val->type) {
3422 case XPATH_UNDEFINED:
3423#ifdef DEBUG_EXPR
3424 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3425#endif
3426 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003427 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003428 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003429 res = xmlXPathCastNodeSetToString(val->nodesetval);
3430 break;
3431 case XPATH_STRING:
3432 return(val);
3433 case XPATH_BOOLEAN:
3434 res = xmlXPathCastBooleanToString(val->boolval);
3435 break;
3436 case XPATH_NUMBER:
3437 res = xmlXPathCastNumberToString(val->floatval);
3438 break;
3439 case XPATH_USERS:
3440 case XPATH_POINT:
3441 case XPATH_RANGE:
3442 case XPATH_LOCATIONSET:
3443 TODO;
3444 break;
3445 }
3446 xmlXPathFreeObject(val);
3447 if (res == NULL)
3448 return(xmlXPathNewCString(""));
3449 return(xmlXPathWrapString(res));
3450}
3451
3452/**
3453 * xmlXPathCastBooleanToNumber:
3454 * @val: a boolean
3455 *
3456 * Converts a boolean to its number value
3457 *
3458 * Returns the number value
3459 */
3460double
3461xmlXPathCastBooleanToNumber(int val) {
3462 if (val)
3463 return(1.0);
3464 return(0.0);
3465}
3466
3467/**
3468 * xmlXPathCastStringToNumber:
3469 * @val: a string
3470 *
3471 * Converts a string to its number value
3472 *
3473 * Returns the number value
3474 */
3475double
3476xmlXPathCastStringToNumber(const xmlChar * val) {
3477 return(xmlXPathStringEvalNumber(val));
3478}
3479
3480/**
3481 * xmlXPathCastNodeToNumber:
3482 * @node: a node
3483 *
3484 * Converts a node to its number value
3485 *
3486 * Returns the number value
3487 */
3488double
3489xmlXPathCastNodeToNumber (xmlNodePtr node) {
3490 xmlChar *strval;
3491 double ret;
3492
3493 if (node == NULL)
3494 return(xmlXPathNAN);
3495 strval = xmlXPathCastNodeToString(node);
3496 if (strval == NULL)
3497 return(xmlXPathNAN);
3498 ret = xmlXPathCastStringToNumber(strval);
3499 xmlFree(strval);
3500
3501 return(ret);
3502}
3503
3504/**
3505 * xmlXPathCastNodeSetToNumber:
3506 * @ns: a node-set
3507 *
3508 * Converts a node-set to its number value
3509 *
3510 * Returns the number value
3511 */
3512double
3513xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3514 xmlChar *str;
3515 double ret;
3516
3517 if (ns == NULL)
3518 return(xmlXPathNAN);
3519 str = xmlXPathCastNodeSetToString(ns);
3520 ret = xmlXPathCastStringToNumber(str);
3521 xmlFree(str);
3522 return(ret);
3523}
3524
3525/**
3526 * xmlXPathCastToNumber:
3527 * @val: an XPath object
3528 *
3529 * Converts an XPath object to its number value
3530 *
3531 * Returns the number value
3532 */
3533double
3534xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3535 double ret = 0.0;
3536
3537 if (val == NULL)
3538 return(xmlXPathNAN);
3539 switch (val->type) {
3540 case XPATH_UNDEFINED:
3541#ifdef DEGUB_EXPR
3542 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3543#endif
3544 ret = xmlXPathNAN;
3545 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003546 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003547 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003548 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3549 break;
3550 case XPATH_STRING:
3551 ret = xmlXPathCastStringToNumber(val->stringval);
3552 break;
3553 case XPATH_NUMBER:
3554 ret = val->floatval;
3555 break;
3556 case XPATH_BOOLEAN:
3557 ret = xmlXPathCastBooleanToNumber(val->boolval);
3558 break;
3559 case XPATH_USERS:
3560 case XPATH_POINT:
3561 case XPATH_RANGE:
3562 case XPATH_LOCATIONSET:
3563 TODO;
3564 ret = xmlXPathNAN;
3565 break;
3566 }
3567 return(ret);
3568}
3569
3570/**
3571 * xmlXPathConvertNumber:
3572 * @val: an XPath object
3573 *
3574 * Converts an existing object to its number() equivalent
3575 *
3576 * Returns the new object, the old one is freed (or the operation
3577 * is done directly on @val)
3578 */
3579xmlXPathObjectPtr
3580xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3581 xmlXPathObjectPtr ret;
3582
3583 if (val == NULL)
3584 return(xmlXPathNewFloat(0.0));
3585 if (val->type == XPATH_NUMBER)
3586 return(val);
3587 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3588 xmlXPathFreeObject(val);
3589 return(ret);
3590}
3591
3592/**
3593 * xmlXPathCastNumberToBoolean:
3594 * @val: a number
3595 *
3596 * Converts a number to its boolean value
3597 *
3598 * Returns the boolean value
3599 */
3600int
3601xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003602 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003603 return(0);
3604 return(1);
3605}
3606
3607/**
3608 * xmlXPathCastStringToBoolean:
3609 * @val: a string
3610 *
3611 * Converts a string to its boolean value
3612 *
3613 * Returns the boolean value
3614 */
3615int
3616xmlXPathCastStringToBoolean (const xmlChar *val) {
3617 if ((val == NULL) || (xmlStrlen(val) == 0))
3618 return(0);
3619 return(1);
3620}
3621
3622/**
3623 * xmlXPathCastNodeSetToBoolean:
3624 * @ns: a node-set
3625 *
3626 * Converts a node-set to its boolean value
3627 *
3628 * Returns the boolean value
3629 */
3630int
3631xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3632 if ((ns == NULL) || (ns->nodeNr == 0))
3633 return(0);
3634 return(1);
3635}
3636
3637/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003638 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003639 * @val: an XPath object
3640 *
3641 * Converts an XPath object to its boolean value
3642 *
3643 * Returns the boolean value
3644 */
3645int
3646xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3647 int ret = 0;
3648
3649 if (val == NULL)
3650 return(0);
3651 switch (val->type) {
3652 case XPATH_UNDEFINED:
3653#ifdef DEBUG_EXPR
3654 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3655#endif
3656 ret = 0;
3657 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003658 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003659 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003660 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3661 break;
3662 case XPATH_STRING:
3663 ret = xmlXPathCastStringToBoolean(val->stringval);
3664 break;
3665 case XPATH_NUMBER:
3666 ret = xmlXPathCastNumberToBoolean(val->floatval);
3667 break;
3668 case XPATH_BOOLEAN:
3669 ret = val->boolval;
3670 break;
3671 case XPATH_USERS:
3672 case XPATH_POINT:
3673 case XPATH_RANGE:
3674 case XPATH_LOCATIONSET:
3675 TODO;
3676 ret = 0;
3677 break;
3678 }
3679 return(ret);
3680}
3681
3682
3683/**
3684 * xmlXPathConvertBoolean:
3685 * @val: an XPath object
3686 *
3687 * Converts an existing object to its boolean() equivalent
3688 *
3689 * Returns the new object, the old one is freed (or the operation
3690 * is done directly on @val)
3691 */
3692xmlXPathObjectPtr
3693xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3694 xmlXPathObjectPtr ret;
3695
3696 if (val == NULL)
3697 return(xmlXPathNewBoolean(0));
3698 if (val->type == XPATH_BOOLEAN)
3699 return(val);
3700 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3701 xmlXPathFreeObject(val);
3702 return(ret);
3703}
3704
Owen Taylor3473f882001-02-23 17:55:21 +00003705/************************************************************************
3706 * *
3707 * Routines to handle XPath contexts *
3708 * *
3709 ************************************************************************/
3710
3711/**
3712 * xmlXPathNewContext:
3713 * @doc: the XML document
3714 *
3715 * Create a new xmlXPathContext
3716 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00003717 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00003718 */
3719xmlXPathContextPtr
3720xmlXPathNewContext(xmlDocPtr doc) {
3721 xmlXPathContextPtr ret;
3722
3723 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3724 if (ret == NULL) {
3725 xmlGenericError(xmlGenericErrorContext,
3726 "xmlXPathNewContext: out of memory\n");
3727 return(NULL);
3728 }
3729 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3730 ret->doc = doc;
3731 ret->node = NULL;
3732
3733 ret->varHash = NULL;
3734
3735 ret->nb_types = 0;
3736 ret->max_types = 0;
3737 ret->types = NULL;
3738
3739 ret->funcHash = xmlHashCreate(0);
3740
3741 ret->nb_axis = 0;
3742 ret->max_axis = 0;
3743 ret->axis = NULL;
3744
3745 ret->nsHash = NULL;
3746 ret->user = NULL;
3747
3748 ret->contextSize = -1;
3749 ret->proximityPosition = -1;
3750
3751 xmlXPathRegisterAllFunctions(ret);
3752
3753 return(ret);
3754}
3755
3756/**
3757 * xmlXPathFreeContext:
3758 * @ctxt: the context to free
3759 *
3760 * Free up an xmlXPathContext
3761 */
3762void
3763xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3764 xmlXPathRegisteredNsCleanup(ctxt);
3765 xmlXPathRegisteredFuncsCleanup(ctxt);
3766 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003767 xmlFree(ctxt);
3768}
3769
3770/************************************************************************
3771 * *
3772 * Routines to handle XPath parser contexts *
3773 * *
3774 ************************************************************************/
3775
3776#define CHECK_CTXT(ctxt) \
3777 if (ctxt == NULL) { \
3778 xmlGenericError(xmlGenericErrorContext, \
3779 "%s:%d Internal error: ctxt == NULL\n", \
3780 __FILE__, __LINE__); \
3781 } \
3782
3783
3784#define CHECK_CONTEXT(ctxt) \
3785 if (ctxt == NULL) { \
3786 xmlGenericError(xmlGenericErrorContext, \
3787 "%s:%d Internal error: no context\n", \
3788 __FILE__, __LINE__); \
3789 } \
3790 else if (ctxt->doc == NULL) { \
3791 xmlGenericError(xmlGenericErrorContext, \
3792 "%s:%d Internal error: no document\n", \
3793 __FILE__, __LINE__); \
3794 } \
3795 else if (ctxt->doc->children == NULL) { \
3796 xmlGenericError(xmlGenericErrorContext, \
3797 "%s:%d Internal error: document without root\n", \
3798 __FILE__, __LINE__); \
3799 } \
3800
3801
3802/**
3803 * xmlXPathNewParserContext:
3804 * @str: the XPath expression
3805 * @ctxt: the XPath context
3806 *
3807 * Create a new xmlXPathParserContext
3808 *
3809 * Returns the xmlXPathParserContext just allocated.
3810 */
3811xmlXPathParserContextPtr
3812xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3813 xmlXPathParserContextPtr ret;
3814
3815 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3816 if (ret == NULL) {
3817 xmlGenericError(xmlGenericErrorContext,
3818 "xmlXPathNewParserContext: out of memory\n");
3819 return(NULL);
3820 }
3821 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3822 ret->cur = ret->base = str;
3823 ret->context = ctxt;
3824
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003825 ret->comp = xmlXPathNewCompExpr();
3826 if (ret->comp == NULL) {
3827 xmlFree(ret->valueTab);
3828 xmlFree(ret);
3829 return(NULL);
3830 }
3831
3832 return(ret);
3833}
3834
3835/**
3836 * xmlXPathCompParserContext:
3837 * @comp: the XPath compiled expression
3838 * @ctxt: the XPath context
3839 *
3840 * Create a new xmlXPathParserContext when processing a compiled expression
3841 *
3842 * Returns the xmlXPathParserContext just allocated.
3843 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003844static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003845xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3846 xmlXPathParserContextPtr ret;
3847
3848 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3849 if (ret == NULL) {
3850 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003851 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003852 return(NULL);
3853 }
3854 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3855
Owen Taylor3473f882001-02-23 17:55:21 +00003856 /* Allocate the value stack */
3857 ret->valueTab = (xmlXPathObjectPtr *)
3858 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003859 if (ret->valueTab == NULL) {
3860 xmlFree(ret);
3861 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003862 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003863 return(NULL);
3864 }
Owen Taylor3473f882001-02-23 17:55:21 +00003865 ret->valueNr = 0;
3866 ret->valueMax = 10;
3867 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003868
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00003869 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003870 ret->comp = comp;
3871
Owen Taylor3473f882001-02-23 17:55:21 +00003872 return(ret);
3873}
3874
3875/**
3876 * xmlXPathFreeParserContext:
3877 * @ctxt: the context to free
3878 *
3879 * Free up an xmlXPathParserContext
3880 */
3881void
3882xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
3883 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003884 xmlFree(ctxt->valueTab);
3885 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003886 if (ctxt->comp)
3887 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00003888 xmlFree(ctxt);
3889}
3890
3891/************************************************************************
3892 * *
3893 * The implicit core function library *
3894 * *
3895 ************************************************************************/
3896
Owen Taylor3473f882001-02-23 17:55:21 +00003897/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00003898 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00003899 * @node: a node pointer
3900 *
3901 * Function computing the beginning of the string value of the node,
3902 * used to speed up comparisons
3903 *
3904 * Returns an int usable as a hash
3905 */
3906static unsigned int
3907xmlXPathNodeValHash(xmlNodePtr node) {
3908 int len = 2;
3909 const xmlChar * string = NULL;
3910 xmlNodePtr tmp = NULL;
3911 unsigned int ret = 0;
3912
3913 if (node == NULL)
3914 return(0);
3915
Daniel Veillard9adc0462003-03-24 18:39:54 +00003916 if (node->type == XML_DOCUMENT_NODE) {
3917 tmp = xmlDocGetRootElement((xmlDocPtr) node);
3918 if (tmp == NULL)
3919 node = node->children;
3920 else
3921 node = tmp;
3922
3923 if (node == NULL)
3924 return(0);
3925 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003926
3927 switch (node->type) {
3928 case XML_COMMENT_NODE:
3929 case XML_PI_NODE:
3930 case XML_CDATA_SECTION_NODE:
3931 case XML_TEXT_NODE:
3932 string = node->content;
3933 if (string == NULL)
3934 return(0);
3935 if (string[0] == 0)
3936 return(0);
3937 return(((unsigned int) string[0]) +
3938 (((unsigned int) string[1]) << 8));
3939 case XML_NAMESPACE_DECL:
3940 string = ((xmlNsPtr)node)->href;
3941 if (string == NULL)
3942 return(0);
3943 if (string[0] == 0)
3944 return(0);
3945 return(((unsigned int) string[0]) +
3946 (((unsigned int) string[1]) << 8));
3947 case XML_ATTRIBUTE_NODE:
3948 tmp = ((xmlAttrPtr) node)->children;
3949 break;
3950 case XML_ELEMENT_NODE:
3951 tmp = node->children;
3952 break;
3953 default:
3954 return(0);
3955 }
3956 while (tmp != NULL) {
3957 switch (tmp->type) {
3958 case XML_COMMENT_NODE:
3959 case XML_PI_NODE:
3960 case XML_CDATA_SECTION_NODE:
3961 case XML_TEXT_NODE:
3962 string = tmp->content;
3963 break;
3964 case XML_NAMESPACE_DECL:
3965 string = ((xmlNsPtr)tmp)->href;
3966 break;
3967 default:
3968 break;
3969 }
3970 if ((string != NULL) && (string[0] != 0)) {
3971 if (string[0] == 0)
3972 return(0);
3973 if (len == 1) {
3974 return(ret + (((unsigned int) string[0]) << 8));
3975 }
3976 if (string[1] == 0) {
3977 len = 1;
3978 ret = (unsigned int) string[0];
3979 } else {
3980 return(((unsigned int) string[0]) +
3981 (((unsigned int) string[1]) << 8));
3982 }
3983 }
3984 /*
3985 * Skip to next node
3986 */
3987 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
3988 if (tmp->children->type != XML_ENTITY_DECL) {
3989 tmp = tmp->children;
3990 continue;
3991 }
3992 }
3993 if (tmp == node)
3994 break;
3995
3996 if (tmp->next != NULL) {
3997 tmp = tmp->next;
3998 continue;
3999 }
4000
4001 do {
4002 tmp = tmp->parent;
4003 if (tmp == NULL)
4004 break;
4005 if (tmp == node) {
4006 tmp = NULL;
4007 break;
4008 }
4009 if (tmp->next != NULL) {
4010 tmp = tmp->next;
4011 break;
4012 }
4013 } while (tmp != NULL);
4014 }
4015 return(ret);
4016}
4017
4018/**
4019 * xmlXPathStringHash:
4020 * @string: a string
4021 *
4022 * Function computing the beginning of the string value of the node,
4023 * used to speed up comparisons
4024 *
4025 * Returns an int usable as a hash
4026 */
4027static unsigned int
4028xmlXPathStringHash(const xmlChar * string) {
4029 if (string == NULL)
4030 return((unsigned int) 0);
4031 if (string[0] == 0)
4032 return(0);
4033 return(((unsigned int) string[0]) +
4034 (((unsigned int) string[1]) << 8));
4035}
4036
4037/**
Owen Taylor3473f882001-02-23 17:55:21 +00004038 * xmlXPathCompareNodeSetFloat:
4039 * @ctxt: the XPath Parser context
4040 * @inf: less than (1) or greater than (0)
4041 * @strict: is the comparison strict
4042 * @arg: the node set
4043 * @f: the value
4044 *
4045 * Implement the compare operation between a nodeset and a number
4046 * @ns < @val (1, 1, ...
4047 * @ns <= @val (1, 0, ...
4048 * @ns > @val (0, 1, ...
4049 * @ns >= @val (0, 0, ...
4050 *
4051 * If one object to be compared is a node-set and the other is a number,
4052 * then the comparison will be true if and only if there is a node in the
4053 * node-set such that the result of performing the comparison on the number
4054 * to be compared and on the result of converting the string-value of that
4055 * node to a number using the number function is true.
4056 *
4057 * Returns 0 or 1 depending on the results of the test.
4058 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004059static int
Owen Taylor3473f882001-02-23 17:55:21 +00004060xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
4061 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
4062 int i, ret = 0;
4063 xmlNodeSetPtr ns;
4064 xmlChar *str2;
4065
4066 if ((f == NULL) || (arg == NULL) ||
4067 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4068 xmlXPathFreeObject(arg);
4069 xmlXPathFreeObject(f);
4070 return(0);
4071 }
4072 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004073 if (ns != NULL) {
4074 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004075 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004076 if (str2 != NULL) {
4077 valuePush(ctxt,
4078 xmlXPathNewString(str2));
4079 xmlFree(str2);
4080 xmlXPathNumberFunction(ctxt, 1);
4081 valuePush(ctxt, xmlXPathObjectCopy(f));
4082 ret = xmlXPathCompareValues(ctxt, inf, strict);
4083 if (ret)
4084 break;
4085 }
4086 }
Owen Taylor3473f882001-02-23 17:55:21 +00004087 }
4088 xmlXPathFreeObject(arg);
4089 xmlXPathFreeObject(f);
4090 return(ret);
4091}
4092
4093/**
4094 * xmlXPathCompareNodeSetString:
4095 * @ctxt: the XPath Parser context
4096 * @inf: less than (1) or greater than (0)
4097 * @strict: is the comparison strict
4098 * @arg: the node set
4099 * @s: the value
4100 *
4101 * Implement the compare operation between a nodeset and a string
4102 * @ns < @val (1, 1, ...
4103 * @ns <= @val (1, 0, ...
4104 * @ns > @val (0, 1, ...
4105 * @ns >= @val (0, 0, ...
4106 *
4107 * If one object to be compared is a node-set and the other is a string,
4108 * then the comparison will be true if and only if there is a node in
4109 * the node-set such that the result of performing the comparison on the
4110 * string-value of the node and the other string is true.
4111 *
4112 * Returns 0 or 1 depending on the results of the test.
4113 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004114static int
Owen Taylor3473f882001-02-23 17:55:21 +00004115xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
4116 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
4117 int i, ret = 0;
4118 xmlNodeSetPtr ns;
4119 xmlChar *str2;
4120
4121 if ((s == NULL) || (arg == NULL) ||
4122 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4123 xmlXPathFreeObject(arg);
4124 xmlXPathFreeObject(s);
4125 return(0);
4126 }
4127 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004128 if (ns != NULL) {
4129 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004130 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004131 if (str2 != NULL) {
4132 valuePush(ctxt,
4133 xmlXPathNewString(str2));
4134 xmlFree(str2);
4135 valuePush(ctxt, xmlXPathObjectCopy(s));
4136 ret = xmlXPathCompareValues(ctxt, inf, strict);
4137 if (ret)
4138 break;
4139 }
4140 }
Owen Taylor3473f882001-02-23 17:55:21 +00004141 }
4142 xmlXPathFreeObject(arg);
4143 xmlXPathFreeObject(s);
4144 return(ret);
4145}
4146
4147/**
4148 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004149 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00004150 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004151 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00004152 * @arg2: the second node set object
4153 *
4154 * Implement the compare operation on nodesets:
4155 *
4156 * If both objects to be compared are node-sets, then the comparison
4157 * will be true if and only if there is a node in the first node-set
4158 * and a node in the second node-set such that the result of performing
4159 * the comparison on the string-values of the two nodes is true.
4160 * ....
4161 * When neither object to be compared is a node-set and the operator
4162 * is <=, <, >= or >, then the objects are compared by converting both
4163 * objects to numbers and comparing the numbers according to IEEE 754.
4164 * ....
4165 * The number function converts its argument to a number as follows:
4166 * - a string that consists of optional whitespace followed by an
4167 * optional minus sign followed by a Number followed by whitespace
4168 * is converted to the IEEE 754 number that is nearest (according
4169 * to the IEEE 754 round-to-nearest rule) to the mathematical value
4170 * represented by the string; any other string is converted to NaN
4171 *
4172 * Conclusion all nodes need to be converted first to their string value
4173 * and then the comparison must be done when possible
4174 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004175static int
4176xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00004177 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4178 int i, j, init = 0;
4179 double val1;
4180 double *values2;
4181 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004182 xmlNodeSetPtr ns1;
4183 xmlNodeSetPtr ns2;
4184
4185 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004186 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4187 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004188 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004189 }
Owen Taylor3473f882001-02-23 17:55:21 +00004190 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004191 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4192 xmlXPathFreeObject(arg1);
4193 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004194 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004195 }
Owen Taylor3473f882001-02-23 17:55:21 +00004196
4197 ns1 = arg1->nodesetval;
4198 ns2 = arg2->nodesetval;
4199
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004200 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004201 xmlXPathFreeObject(arg1);
4202 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004203 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004204 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004205 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004206 xmlXPathFreeObject(arg1);
4207 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004208 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004209 }
Owen Taylor3473f882001-02-23 17:55:21 +00004210
4211 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4212 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004213 xmlXPathFreeObject(arg1);
4214 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004215 return(0);
4216 }
4217 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004218 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004219 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004220 continue;
4221 for (j = 0;j < ns2->nodeNr;j++) {
4222 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004223 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004224 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004225 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004226 continue;
4227 if (inf && strict)
4228 ret = (val1 < values2[j]);
4229 else if (inf && !strict)
4230 ret = (val1 <= values2[j]);
4231 else if (!inf && strict)
4232 ret = (val1 > values2[j]);
4233 else if (!inf && !strict)
4234 ret = (val1 >= values2[j]);
4235 if (ret)
4236 break;
4237 }
4238 if (ret)
4239 break;
4240 init = 1;
4241 }
4242 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004243 xmlXPathFreeObject(arg1);
4244 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004245 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004246}
4247
4248/**
4249 * xmlXPathCompareNodeSetValue:
4250 * @ctxt: the XPath Parser context
4251 * @inf: less than (1) or greater than (0)
4252 * @strict: is the comparison strict
4253 * @arg: the node set
4254 * @val: the value
4255 *
4256 * Implement the compare operation between a nodeset and a value
4257 * @ns < @val (1, 1, ...
4258 * @ns <= @val (1, 0, ...
4259 * @ns > @val (0, 1, ...
4260 * @ns >= @val (0, 0, ...
4261 *
4262 * If one object to be compared is a node-set and the other is a boolean,
4263 * then the comparison will be true if and only if the result of performing
4264 * the comparison on the boolean and on the result of converting
4265 * the node-set to a boolean using the boolean function is true.
4266 *
4267 * Returns 0 or 1 depending on the results of the test.
4268 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004269static int
Owen Taylor3473f882001-02-23 17:55:21 +00004270xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4271 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4272 if ((val == NULL) || (arg == NULL) ||
4273 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4274 return(0);
4275
4276 switch(val->type) {
4277 case XPATH_NUMBER:
4278 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4279 case XPATH_NODESET:
4280 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004281 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004282 case XPATH_STRING:
4283 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4284 case XPATH_BOOLEAN:
4285 valuePush(ctxt, arg);
4286 xmlXPathBooleanFunction(ctxt, 1);
4287 valuePush(ctxt, val);
4288 return(xmlXPathCompareValues(ctxt, inf, strict));
4289 default:
4290 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004291 }
4292 return(0);
4293}
4294
4295/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004296 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00004297 * @arg: the nodeset object argument
4298 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00004299 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004300 *
4301 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4302 * If one object to be compared is a node-set and the other is a string,
4303 * then the comparison will be true if and only if there is a node in
4304 * the node-set such that the result of performing the comparison on the
4305 * string-value of the node and the other string is true.
4306 *
4307 * Returns 0 or 1 depending on the results of the test.
4308 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004309static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004310xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004311{
Owen Taylor3473f882001-02-23 17:55:21 +00004312 int i;
4313 xmlNodeSetPtr ns;
4314 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004315 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004316
4317 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004318 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4319 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004320 ns = arg->nodesetval;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004321 hash = xmlXPathStringHash(str);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004322 if (ns == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004323 return (0);
Daniel Veillard73c9c042001-07-05 20:02:54 +00004324 if (ns->nodeNr <= 0) {
4325 if (hash == 0)
William M. Brack0c022ad2002-07-12 00:56:01 +00004326 return(neq ^ 1);
4327 return(neq);
Daniel Veillard73c9c042001-07-05 20:02:54 +00004328 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004329 for (i = 0; i < ns->nodeNr; i++) {
4330 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4331 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4332 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4333 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004334 if (neq)
4335 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004336 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00004337 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
4338 if (neq)
4339 continue;
4340 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00004341 } else if (neq) {
4342 if (str2 != NULL)
4343 xmlFree(str2);
4344 return (1);
4345 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004346 if (str2 != NULL)
4347 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004348 } else if (neq)
4349 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00004350 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004351 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004352}
4353
4354/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004355 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00004356 * @arg: the nodeset object argument
4357 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00004358 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004359 *
4360 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4361 * If one object to be compared is a node-set and the other is a number,
4362 * then the comparison will be true if and only if there is a node in
4363 * the node-set such that the result of performing the comparison on the
4364 * number to be compared and on the result of converting the string-value
4365 * of that node to a number using the number function is true.
4366 *
4367 * Returns 0 or 1 depending on the results of the test.
4368 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004369static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004370xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
4371 xmlXPathObjectPtr arg, double f, int neq) {
4372 int i, ret=0;
4373 xmlNodeSetPtr ns;
4374 xmlChar *str2;
4375 xmlXPathObjectPtr val;
4376 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00004377
4378 if ((arg == NULL) ||
4379 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4380 return(0);
4381
William M. Brack0c022ad2002-07-12 00:56:01 +00004382 ns = arg->nodesetval;
4383 if (ns != NULL) {
4384 for (i=0;i<ns->nodeNr;i++) {
4385 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4386 if (str2 != NULL) {
4387 valuePush(ctxt, xmlXPathNewString(str2));
4388 xmlFree(str2);
4389 xmlXPathNumberFunction(ctxt, 1);
4390 val = valuePop(ctxt);
4391 v = val->floatval;
4392 xmlXPathFreeObject(val);
4393 if (!xmlXPathIsNaN(v)) {
4394 if ((!neq) && (v==f)) {
4395 ret = 1;
4396 break;
4397 } else if ((neq) && (v!=f)) {
4398 ret = 1;
4399 break;
4400 }
4401 }
4402 }
4403 }
4404 }
4405
4406 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004407}
4408
4409
4410/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004411 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00004412 * @arg1: first nodeset object argument
4413 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00004414 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004415 *
William M. Brack0c022ad2002-07-12 00:56:01 +00004416 * Implement the equal / not equal operation on XPath nodesets:
4417 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00004418 * If both objects to be compared are node-sets, then the comparison
4419 * will be true if and only if there is a node in the first node-set and
4420 * a node in the second node-set such that the result of performing the
4421 * comparison on the string-values of the two nodes is true.
4422 *
4423 * (needless to say, this is a costly operation)
4424 *
4425 * Returns 0 or 1 depending on the results of the test.
4426 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004427static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004428xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00004429 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004430 unsigned int *hashs1;
4431 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004432 xmlChar **values1;
4433 xmlChar **values2;
4434 int ret = 0;
4435 xmlNodeSetPtr ns1;
4436 xmlNodeSetPtr ns2;
4437
4438 if ((arg1 == NULL) ||
4439 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4440 return(0);
4441 if ((arg2 == NULL) ||
4442 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4443 return(0);
4444
4445 ns1 = arg1->nodesetval;
4446 ns2 = arg2->nodesetval;
4447
Daniel Veillard911f49a2001-04-07 15:39:35 +00004448 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004449 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004450 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004451 return(0);
4452
4453 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00004454 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00004455 */
William M. Brack0c022ad2002-07-12 00:56:01 +00004456 if (neq == 0)
4457 for (i = 0;i < ns1->nodeNr;i++)
4458 for (j = 0;j < ns2->nodeNr;j++)
4459 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4460 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00004461
4462 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
4463 if (values1 == NULL)
4464 return(0);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004465 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4466 if (hashs1 == NULL) {
4467 xmlFree(values1);
4468 return(0);
4469 }
Owen Taylor3473f882001-02-23 17:55:21 +00004470 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4471 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4472 if (values2 == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004473 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004474 xmlFree(values1);
4475 return(0);
4476 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004477 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4478 if (hashs2 == NULL) {
4479 xmlFree(hashs1);
4480 xmlFree(values1);
4481 xmlFree(values2);
4482 return(0);
4483 }
Owen Taylor3473f882001-02-23 17:55:21 +00004484 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4485 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004486 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004487 for (j = 0;j < ns2->nodeNr;j++) {
4488 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004489 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004490 if (hashs1[i] != hashs2[j]) {
4491 if (neq) {
4492 ret = 1;
4493 break;
4494 }
4495 }
4496 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004497 if (values1[i] == NULL)
4498 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4499 if (values2[j] == NULL)
4500 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004501 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004502 if (ret)
4503 break;
4504 }
Owen Taylor3473f882001-02-23 17:55:21 +00004505 }
4506 if (ret)
4507 break;
4508 }
4509 for (i = 0;i < ns1->nodeNr;i++)
4510 if (values1[i] != NULL)
4511 xmlFree(values1[i]);
4512 for (j = 0;j < ns2->nodeNr;j++)
4513 if (values2[j] != NULL)
4514 xmlFree(values2[j]);
4515 xmlFree(values1);
4516 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004517 xmlFree(hashs1);
4518 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004519 return(ret);
4520}
4521
William M. Brack0c022ad2002-07-12 00:56:01 +00004522static int
4523xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
4524 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00004525 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00004526 /*
4527 *At this point we are assured neither arg1 nor arg2
4528 *is a nodeset, so we can just pick the appropriate routine.
4529 */
Owen Taylor3473f882001-02-23 17:55:21 +00004530 switch (arg1->type) {
4531 case XPATH_UNDEFINED:
4532#ifdef DEBUG_EXPR
4533 xmlGenericError(xmlGenericErrorContext,
4534 "Equal: undefined\n");
4535#endif
4536 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004537 case XPATH_BOOLEAN:
4538 switch (arg2->type) {
4539 case XPATH_UNDEFINED:
4540#ifdef DEBUG_EXPR
4541 xmlGenericError(xmlGenericErrorContext,
4542 "Equal: undefined\n");
4543#endif
4544 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004545 case XPATH_BOOLEAN:
4546#ifdef DEBUG_EXPR
4547 xmlGenericError(xmlGenericErrorContext,
4548 "Equal: %d boolean %d \n",
4549 arg1->boolval, arg2->boolval);
4550#endif
4551 ret = (arg1->boolval == arg2->boolval);
4552 break;
4553 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00004554 ret = (arg1->boolval ==
4555 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004556 break;
4557 case XPATH_STRING:
4558 if ((arg2->stringval == NULL) ||
4559 (arg2->stringval[0] == 0)) ret = 0;
4560 else
4561 ret = 1;
4562 ret = (arg1->boolval == ret);
4563 break;
4564 case XPATH_USERS:
4565 case XPATH_POINT:
4566 case XPATH_RANGE:
4567 case XPATH_LOCATIONSET:
4568 TODO
4569 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004570 case XPATH_NODESET:
4571 case XPATH_XSLT_TREE:
4572 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004573 }
4574 break;
4575 case XPATH_NUMBER:
4576 switch (arg2->type) {
4577 case XPATH_UNDEFINED:
4578#ifdef DEBUG_EXPR
4579 xmlGenericError(xmlGenericErrorContext,
4580 "Equal: undefined\n");
4581#endif
4582 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004583 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00004584 ret = (arg2->boolval==
4585 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004586 break;
4587 case XPATH_STRING:
4588 valuePush(ctxt, arg2);
4589 xmlXPathNumberFunction(ctxt, 1);
4590 arg2 = valuePop(ctxt);
4591 /* no break on purpose */
4592 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004593 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004594 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4595 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004596 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4597 if (xmlXPathIsInf(arg2->floatval) == 1)
4598 ret = 1;
4599 else
4600 ret = 0;
4601 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4602 if (xmlXPathIsInf(arg2->floatval) == -1)
4603 ret = 1;
4604 else
4605 ret = 0;
4606 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4607 if (xmlXPathIsInf(arg1->floatval) == 1)
4608 ret = 1;
4609 else
4610 ret = 0;
4611 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4612 if (xmlXPathIsInf(arg1->floatval) == -1)
4613 ret = 1;
4614 else
4615 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004616 } else {
4617 ret = (arg1->floatval == arg2->floatval);
4618 }
Owen Taylor3473f882001-02-23 17:55:21 +00004619 break;
4620 case XPATH_USERS:
4621 case XPATH_POINT:
4622 case XPATH_RANGE:
4623 case XPATH_LOCATIONSET:
4624 TODO
4625 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004626 case XPATH_NODESET:
4627 case XPATH_XSLT_TREE:
4628 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004629 }
4630 break;
4631 case XPATH_STRING:
4632 switch (arg2->type) {
4633 case XPATH_UNDEFINED:
4634#ifdef DEBUG_EXPR
4635 xmlGenericError(xmlGenericErrorContext,
4636 "Equal: undefined\n");
4637#endif
4638 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004639 case XPATH_BOOLEAN:
4640 if ((arg1->stringval == NULL) ||
4641 (arg1->stringval[0] == 0)) ret = 0;
4642 else
4643 ret = 1;
4644 ret = (arg2->boolval == ret);
4645 break;
4646 case XPATH_STRING:
4647 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4648 break;
4649 case XPATH_NUMBER:
4650 valuePush(ctxt, arg1);
4651 xmlXPathNumberFunction(ctxt, 1);
4652 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004653 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004654 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4655 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004656 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4657 if (xmlXPathIsInf(arg2->floatval) == 1)
4658 ret = 1;
4659 else
4660 ret = 0;
4661 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4662 if (xmlXPathIsInf(arg2->floatval) == -1)
4663 ret = 1;
4664 else
4665 ret = 0;
4666 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4667 if (xmlXPathIsInf(arg1->floatval) == 1)
4668 ret = 1;
4669 else
4670 ret = 0;
4671 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4672 if (xmlXPathIsInf(arg1->floatval) == -1)
4673 ret = 1;
4674 else
4675 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004676 } else {
4677 ret = (arg1->floatval == arg2->floatval);
4678 }
Owen Taylor3473f882001-02-23 17:55:21 +00004679 break;
4680 case XPATH_USERS:
4681 case XPATH_POINT:
4682 case XPATH_RANGE:
4683 case XPATH_LOCATIONSET:
4684 TODO
4685 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004686 case XPATH_NODESET:
4687 case XPATH_XSLT_TREE:
4688 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004689 }
4690 break;
4691 case XPATH_USERS:
4692 case XPATH_POINT:
4693 case XPATH_RANGE:
4694 case XPATH_LOCATIONSET:
4695 TODO
4696 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004697 case XPATH_NODESET:
4698 case XPATH_XSLT_TREE:
4699 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004700 }
4701 xmlXPathFreeObject(arg1);
4702 xmlXPathFreeObject(arg2);
4703 return(ret);
4704}
4705
William M. Brack0c022ad2002-07-12 00:56:01 +00004706/**
4707 * xmlXPathEqualValues:
4708 * @ctxt: the XPath Parser context
4709 *
4710 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4711 *
4712 * Returns 0 or 1 depending on the results of the test.
4713 */
4714int
4715xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4716 xmlXPathObjectPtr arg1, arg2, argtmp;
4717 int ret = 0;
4718
4719 arg2 = valuePop(ctxt);
4720 arg1 = valuePop(ctxt);
4721 if ((arg1 == NULL) || (arg2 == NULL)) {
4722 if (arg1 != NULL)
4723 xmlXPathFreeObject(arg1);
4724 else
4725 xmlXPathFreeObject(arg2);
4726 XP_ERROR0(XPATH_INVALID_OPERAND);
4727 }
4728
4729 if (arg1 == arg2) {
4730#ifdef DEBUG_EXPR
4731 xmlGenericError(xmlGenericErrorContext,
4732 "Equal: by pointer\n");
4733#endif
4734 return(1);
4735 }
4736
4737 /*
4738 *If either argument is a nodeset, it's a 'special case'
4739 */
4740 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4741 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4742 /*
4743 *Hack it to assure arg1 is the nodeset
4744 */
4745 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4746 argtmp = arg2;
4747 arg2 = arg1;
4748 arg1 = argtmp;
4749 }
4750 switch (arg2->type) {
4751 case XPATH_UNDEFINED:
4752#ifdef DEBUG_EXPR
4753 xmlGenericError(xmlGenericErrorContext,
4754 "Equal: undefined\n");
4755#endif
4756 break;
4757 case XPATH_NODESET:
4758 case XPATH_XSLT_TREE:
4759 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
4760 break;
4761 case XPATH_BOOLEAN:
4762 if ((arg1->nodesetval == NULL) ||
4763 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4764 else
4765 ret = 1;
4766 ret = (ret == arg2->boolval);
4767 break;
4768 case XPATH_NUMBER:
4769 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
4770 break;
4771 case XPATH_STRING:
4772 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
4773 break;
4774 case XPATH_USERS:
4775 case XPATH_POINT:
4776 case XPATH_RANGE:
4777 case XPATH_LOCATIONSET:
4778 TODO
4779 break;
4780 }
4781 xmlXPathFreeObject(arg1);
4782 xmlXPathFreeObject(arg2);
4783 return(ret);
4784 }
4785
4786 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4787}
4788
4789/**
4790 * xmlXPathNotEqualValues:
4791 * @ctxt: the XPath Parser context
4792 *
4793 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4794 *
4795 * Returns 0 or 1 depending on the results of the test.
4796 */
4797int
4798xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
4799 xmlXPathObjectPtr arg1, arg2, argtmp;
4800 int ret = 0;
4801
4802 arg2 = valuePop(ctxt);
4803 arg1 = valuePop(ctxt);
4804 if ((arg1 == NULL) || (arg2 == NULL)) {
4805 if (arg1 != NULL)
4806 xmlXPathFreeObject(arg1);
4807 else
4808 xmlXPathFreeObject(arg2);
4809 XP_ERROR0(XPATH_INVALID_OPERAND);
4810 }
4811
4812 if (arg1 == arg2) {
4813#ifdef DEBUG_EXPR
4814 xmlGenericError(xmlGenericErrorContext,
4815 "NotEqual: by pointer\n");
4816#endif
4817 return(0);
4818 }
4819
4820 /*
4821 *If either argument is a nodeset, it's a 'special case'
4822 */
4823 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4824 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4825 /*
4826 *Hack it to assure arg1 is the nodeset
4827 */
4828 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4829 argtmp = arg2;
4830 arg2 = arg1;
4831 arg1 = argtmp;
4832 }
4833 switch (arg2->type) {
4834 case XPATH_UNDEFINED:
4835#ifdef DEBUG_EXPR
4836 xmlGenericError(xmlGenericErrorContext,
4837 "NotEqual: undefined\n");
4838#endif
4839 break;
4840 case XPATH_NODESET:
4841 case XPATH_XSLT_TREE:
4842 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
4843 break;
4844 case XPATH_BOOLEAN:
4845 if ((arg1->nodesetval == NULL) ||
4846 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4847 else
4848 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00004849 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00004850 break;
4851 case XPATH_NUMBER:
4852 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
4853 break;
4854 case XPATH_STRING:
4855 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
4856 break;
4857 case XPATH_USERS:
4858 case XPATH_POINT:
4859 case XPATH_RANGE:
4860 case XPATH_LOCATIONSET:
4861 TODO
4862 break;
4863 }
4864 xmlXPathFreeObject(arg1);
4865 xmlXPathFreeObject(arg2);
4866 return(ret);
4867 }
4868
4869 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4870}
Owen Taylor3473f882001-02-23 17:55:21 +00004871
4872/**
4873 * xmlXPathCompareValues:
4874 * @ctxt: the XPath Parser context
4875 * @inf: less than (1) or greater than (0)
4876 * @strict: is the comparison strict
4877 *
4878 * Implement the compare operation on XPath objects:
4879 * @arg1 < @arg2 (1, 1, ...
4880 * @arg1 <= @arg2 (1, 0, ...
4881 * @arg1 > @arg2 (0, 1, ...
4882 * @arg1 >= @arg2 (0, 0, ...
4883 *
4884 * When neither object to be compared is a node-set and the operator is
4885 * <=, <, >=, >, then the objects are compared by converted both objects
4886 * to numbers and comparing the numbers according to IEEE 754. The <
4887 * comparison will be true if and only if the first number is less than the
4888 * second number. The <= comparison will be true if and only if the first
4889 * number is less than or equal to the second number. The > comparison
4890 * will be true if and only if the first number is greater than the second
4891 * number. The >= comparison will be true if and only if the first number
4892 * is greater than or equal to the second number.
4893 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004894 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00004895 */
4896int
4897xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004898 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004899 xmlXPathObjectPtr arg1, arg2;
4900
William M. Brack0c022ad2002-07-12 00:56:01 +00004901 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00004902 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00004903 if ((arg1 == NULL) || (arg2 == NULL)) {
4904 if (arg1 != NULL)
4905 xmlXPathFreeObject(arg1);
4906 else
4907 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004908 XP_ERROR0(XPATH_INVALID_OPERAND);
4909 }
4910
William M. Brack0c022ad2002-07-12 00:56:01 +00004911 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4912 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4913 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
4914 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004915 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004916 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00004917 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004918 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
4919 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004920 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004921 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
4922 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00004923 }
4924 }
4925 return(ret);
4926 }
4927
4928 if (arg1->type != XPATH_NUMBER) {
4929 valuePush(ctxt, arg1);
4930 xmlXPathNumberFunction(ctxt, 1);
4931 arg1 = valuePop(ctxt);
4932 }
4933 if (arg1->type != XPATH_NUMBER) {
4934 xmlXPathFreeObject(arg1);
4935 xmlXPathFreeObject(arg2);
4936 XP_ERROR0(XPATH_INVALID_OPERAND);
4937 }
4938 if (arg2->type != XPATH_NUMBER) {
4939 valuePush(ctxt, arg2);
4940 xmlXPathNumberFunction(ctxt, 1);
4941 arg2 = valuePop(ctxt);
4942 }
4943 if (arg2->type != XPATH_NUMBER) {
4944 xmlXPathFreeObject(arg1);
4945 xmlXPathFreeObject(arg2);
4946 XP_ERROR0(XPATH_INVALID_OPERAND);
4947 }
4948 /*
4949 * Add tests for infinity and nan
4950 * => feedback on 3.4 for Inf and NaN
4951 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004952 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00004953 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004954 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004955 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004956 arg1i=xmlXPathIsInf(arg1->floatval);
4957 arg2i=xmlXPathIsInf(arg2->floatval);
4958 if (inf && strict) {
4959 if ((arg1i == -1 && arg2i != -1) ||
4960 (arg2i == 1 && arg1i != 1)) {
4961 ret = 1;
4962 } else if (arg1i == 0 && arg2i == 0) {
4963 ret = (arg1->floatval < arg2->floatval);
4964 } else {
4965 ret = 0;
4966 }
4967 }
4968 else if (inf && !strict) {
4969 if (arg1i == -1 || arg2i == 1) {
4970 ret = 1;
4971 } else if (arg1i == 0 && arg2i == 0) {
4972 ret = (arg1->floatval <= arg2->floatval);
4973 } else {
4974 ret = 0;
4975 }
4976 }
4977 else if (!inf && strict) {
4978 if ((arg1i == 1 && arg2i != 1) ||
4979 (arg2i == -1 && arg1i != -1)) {
4980 ret = 1;
4981 } else if (arg1i == 0 && arg2i == 0) {
4982 ret = (arg1->floatval > arg2->floatval);
4983 } else {
4984 ret = 0;
4985 }
4986 }
4987 else if (!inf && !strict) {
4988 if (arg1i == 1 || arg2i == -1) {
4989 ret = 1;
4990 } else if (arg1i == 0 && arg2i == 0) {
4991 ret = (arg1->floatval >= arg2->floatval);
4992 } else {
4993 ret = 0;
4994 }
4995 }
Daniel Veillard21458c82002-03-27 16:12:22 +00004996 }
Owen Taylor3473f882001-02-23 17:55:21 +00004997 xmlXPathFreeObject(arg1);
4998 xmlXPathFreeObject(arg2);
4999 return(ret);
5000}
5001
5002/**
5003 * xmlXPathValueFlipSign:
5004 * @ctxt: the XPath Parser context
5005 *
5006 * Implement the unary - operation on an XPath object
5007 * The numeric operators convert their operands to numbers as if
5008 * by calling the number function.
5009 */
5010void
5011xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005012 CAST_TO_NUMBER;
5013 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005014 if (xmlXPathIsNaN(ctxt->value->floatval))
5015 ctxt->value->floatval=xmlXPathNAN;
5016 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
5017 ctxt->value->floatval=xmlXPathNINF;
5018 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
5019 ctxt->value->floatval=xmlXPathPINF;
5020 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005021 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
5022 ctxt->value->floatval = xmlXPathNZERO;
5023 else
5024 ctxt->value->floatval = 0;
5025 }
5026 else
5027 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00005028}
5029
5030/**
5031 * xmlXPathAddValues:
5032 * @ctxt: the XPath Parser context
5033 *
5034 * Implement the add operation on XPath objects:
5035 * The numeric operators convert their operands to numbers as if
5036 * by calling the number function.
5037 */
5038void
5039xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
5040 xmlXPathObjectPtr arg;
5041 double val;
5042
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005043 arg = valuePop(ctxt);
5044 if (arg == NULL)
5045 XP_ERROR(XPATH_INVALID_OPERAND);
5046 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005047 xmlXPathFreeObject(arg);
5048
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005049 CAST_TO_NUMBER;
5050 CHECK_TYPE(XPATH_NUMBER);
5051 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00005052}
5053
5054/**
5055 * xmlXPathSubValues:
5056 * @ctxt: the XPath Parser context
5057 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005058 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00005059 * The numeric operators convert their operands to numbers as if
5060 * by calling the number function.
5061 */
5062void
5063xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
5064 xmlXPathObjectPtr arg;
5065 double val;
5066
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005067 arg = valuePop(ctxt);
5068 if (arg == NULL)
5069 XP_ERROR(XPATH_INVALID_OPERAND);
5070 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005071 xmlXPathFreeObject(arg);
5072
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005073 CAST_TO_NUMBER;
5074 CHECK_TYPE(XPATH_NUMBER);
5075 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005076}
5077
5078/**
5079 * xmlXPathMultValues:
5080 * @ctxt: the XPath Parser context
5081 *
5082 * Implement the multiply operation on XPath objects:
5083 * The numeric operators convert their operands to numbers as if
5084 * by calling the number function.
5085 */
5086void
5087xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
5088 xmlXPathObjectPtr arg;
5089 double val;
5090
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005091 arg = valuePop(ctxt);
5092 if (arg == NULL)
5093 XP_ERROR(XPATH_INVALID_OPERAND);
5094 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005095 xmlXPathFreeObject(arg);
5096
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005097 CAST_TO_NUMBER;
5098 CHECK_TYPE(XPATH_NUMBER);
5099 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005100}
5101
5102/**
5103 * xmlXPathDivValues:
5104 * @ctxt: the XPath Parser context
5105 *
5106 * Implement the div operation on XPath objects @arg1 / @arg2:
5107 * The numeric operators convert their operands to numbers as if
5108 * by calling the number function.
5109 */
5110void
5111xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
5112 xmlXPathObjectPtr arg;
5113 double val;
5114
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005115 arg = valuePop(ctxt);
5116 if (arg == NULL)
5117 XP_ERROR(XPATH_INVALID_OPERAND);
5118 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005119 xmlXPathFreeObject(arg);
5120
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005121 CAST_TO_NUMBER;
5122 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005123 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
5124 ctxt->value->floatval = xmlXPathNAN;
5125 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005126 if (ctxt->value->floatval == 0)
5127 ctxt->value->floatval = xmlXPathNAN;
5128 else if (ctxt->value->floatval > 0)
5129 ctxt->value->floatval = xmlXPathNINF;
5130 else if (ctxt->value->floatval < 0)
5131 ctxt->value->floatval = xmlXPathPINF;
5132 }
5133 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00005134 if (ctxt->value->floatval == 0)
5135 ctxt->value->floatval = xmlXPathNAN;
5136 else if (ctxt->value->floatval > 0)
5137 ctxt->value->floatval = xmlXPathPINF;
5138 else if (ctxt->value->floatval < 0)
5139 ctxt->value->floatval = xmlXPathNINF;
5140 } else
5141 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005142}
5143
5144/**
5145 * xmlXPathModValues:
5146 * @ctxt: the XPath Parser context
5147 *
5148 * Implement the mod operation on XPath objects: @arg1 / @arg2
5149 * The numeric operators convert their operands to numbers as if
5150 * by calling the number function.
5151 */
5152void
5153xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
5154 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005155 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00005156
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005157 arg = valuePop(ctxt);
5158 if (arg == NULL)
5159 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005160 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005161 xmlXPathFreeObject(arg);
5162
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005163 CAST_TO_NUMBER;
5164 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005165 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00005166 if (arg2 == 0)
5167 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005168 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00005169 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005170 }
Owen Taylor3473f882001-02-23 17:55:21 +00005171}
5172
5173/************************************************************************
5174 * *
5175 * The traversal functions *
5176 * *
5177 ************************************************************************/
5178
Owen Taylor3473f882001-02-23 17:55:21 +00005179/*
5180 * A traversal function enumerates nodes along an axis.
5181 * Initially it must be called with NULL, and it indicates
5182 * termination on the axis by returning NULL.
5183 */
5184typedef xmlNodePtr (*xmlXPathTraversalFunction)
5185 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
5186
5187/**
5188 * xmlXPathNextSelf:
5189 * @ctxt: the XPath Parser context
5190 * @cur: the current node in the traversal
5191 *
5192 * Traversal function for the "self" direction
5193 * The self axis contains just the context node itself
5194 *
5195 * Returns the next element following that axis
5196 */
5197xmlNodePtr
5198xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5199 if (cur == NULL)
5200 return(ctxt->context->node);
5201 return(NULL);
5202}
5203
5204/**
5205 * xmlXPathNextChild:
5206 * @ctxt: the XPath Parser context
5207 * @cur: the current node in the traversal
5208 *
5209 * Traversal function for the "child" direction
5210 * The child axis contains the children of the context node in document order.
5211 *
5212 * Returns the next element following that axis
5213 */
5214xmlNodePtr
5215xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5216 if (cur == NULL) {
5217 if (ctxt->context->node == NULL) return(NULL);
5218 switch (ctxt->context->node->type) {
5219 case XML_ELEMENT_NODE:
5220 case XML_TEXT_NODE:
5221 case XML_CDATA_SECTION_NODE:
5222 case XML_ENTITY_REF_NODE:
5223 case XML_ENTITY_NODE:
5224 case XML_PI_NODE:
5225 case XML_COMMENT_NODE:
5226 case XML_NOTATION_NODE:
5227 case XML_DTD_NODE:
5228 return(ctxt->context->node->children);
5229 case XML_DOCUMENT_NODE:
5230 case XML_DOCUMENT_TYPE_NODE:
5231 case XML_DOCUMENT_FRAG_NODE:
5232 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005233#ifdef LIBXML_DOCB_ENABLED
5234 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005235#endif
5236 return(((xmlDocPtr) ctxt->context->node)->children);
5237 case XML_ELEMENT_DECL:
5238 case XML_ATTRIBUTE_DECL:
5239 case XML_ENTITY_DECL:
5240 case XML_ATTRIBUTE_NODE:
5241 case XML_NAMESPACE_DECL:
5242 case XML_XINCLUDE_START:
5243 case XML_XINCLUDE_END:
5244 return(NULL);
5245 }
5246 return(NULL);
5247 }
5248 if ((cur->type == XML_DOCUMENT_NODE) ||
5249 (cur->type == XML_HTML_DOCUMENT_NODE))
5250 return(NULL);
5251 return(cur->next);
5252}
5253
5254/**
5255 * xmlXPathNextDescendant:
5256 * @ctxt: the XPath Parser context
5257 * @cur: the current node in the traversal
5258 *
5259 * Traversal function for the "descendant" direction
5260 * the descendant axis contains the descendants of the context node in document
5261 * order; a descendant is a child or a child of a child and so on.
5262 *
5263 * Returns the next element following that axis
5264 */
5265xmlNodePtr
5266xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5267 if (cur == NULL) {
5268 if (ctxt->context->node == NULL)
5269 return(NULL);
5270 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5271 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5272 return(NULL);
5273
5274 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5275 return(ctxt->context->doc->children);
5276 return(ctxt->context->node->children);
5277 }
5278
Daniel Veillard567e1b42001-08-01 15:53:47 +00005279 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00005280 /*
5281 * Do not descend on entities declarations
5282 */
5283 if (cur->children->type != XML_ENTITY_DECL) {
5284 cur = cur->children;
5285 /*
5286 * Skip DTDs
5287 */
5288 if (cur->type != XML_DTD_NODE)
5289 return(cur);
5290 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00005291 }
5292
5293 if (cur == ctxt->context->node) return(NULL);
5294
Daniel Veillard68e9e742002-11-16 15:35:11 +00005295 while (cur->next != NULL) {
5296 cur = cur->next;
5297 if ((cur->type != XML_ENTITY_DECL) &&
5298 (cur->type != XML_DTD_NODE))
5299 return(cur);
5300 }
Owen Taylor3473f882001-02-23 17:55:21 +00005301
5302 do {
5303 cur = cur->parent;
5304 if (cur == NULL) return(NULL);
5305 if (cur == ctxt->context->node) return(NULL);
5306 if (cur->next != NULL) {
5307 cur = cur->next;
5308 return(cur);
5309 }
5310 } while (cur != NULL);
5311 return(cur);
5312}
5313
5314/**
5315 * xmlXPathNextDescendantOrSelf:
5316 * @ctxt: the XPath Parser context
5317 * @cur: the current node in the traversal
5318 *
5319 * Traversal function for the "descendant-or-self" direction
5320 * the descendant-or-self axis contains the context node and the descendants
5321 * of the context node in document order; thus the context node is the first
5322 * node on the axis, and the first child of the context node is the second node
5323 * on the axis
5324 *
5325 * Returns the next element following that axis
5326 */
5327xmlNodePtr
5328xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5329 if (cur == NULL) {
5330 if (ctxt->context->node == NULL)
5331 return(NULL);
5332 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5333 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5334 return(NULL);
5335 return(ctxt->context->node);
5336 }
5337
5338 return(xmlXPathNextDescendant(ctxt, cur));
5339}
5340
5341/**
5342 * xmlXPathNextParent:
5343 * @ctxt: the XPath Parser context
5344 * @cur: the current node in the traversal
5345 *
5346 * Traversal function for the "parent" direction
5347 * The parent axis contains the parent of the context node, if there is one.
5348 *
5349 * Returns the next element following that axis
5350 */
5351xmlNodePtr
5352xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5353 /*
5354 * the parent of an attribute or namespace node is the element
5355 * to which the attribute or namespace node is attached
5356 * Namespace handling !!!
5357 */
5358 if (cur == NULL) {
5359 if (ctxt->context->node == NULL) return(NULL);
5360 switch (ctxt->context->node->type) {
5361 case XML_ELEMENT_NODE:
5362 case XML_TEXT_NODE:
5363 case XML_CDATA_SECTION_NODE:
5364 case XML_ENTITY_REF_NODE:
5365 case XML_ENTITY_NODE:
5366 case XML_PI_NODE:
5367 case XML_COMMENT_NODE:
5368 case XML_NOTATION_NODE:
5369 case XML_DTD_NODE:
5370 case XML_ELEMENT_DECL:
5371 case XML_ATTRIBUTE_DECL:
5372 case XML_XINCLUDE_START:
5373 case XML_XINCLUDE_END:
5374 case XML_ENTITY_DECL:
5375 if (ctxt->context->node->parent == NULL)
5376 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005377 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005378 ((ctxt->context->node->parent->name[0] == ' ') ||
5379 (xmlStrEqual(ctxt->context->node->parent->name,
5380 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005381 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005382 return(ctxt->context->node->parent);
5383 case XML_ATTRIBUTE_NODE: {
5384 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5385
5386 return(att->parent);
5387 }
5388 case XML_DOCUMENT_NODE:
5389 case XML_DOCUMENT_TYPE_NODE:
5390 case XML_DOCUMENT_FRAG_NODE:
5391 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005392#ifdef LIBXML_DOCB_ENABLED
5393 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005394#endif
5395 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005396 case XML_NAMESPACE_DECL: {
5397 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5398
5399 if ((ns->next != NULL) &&
5400 (ns->next->type != XML_NAMESPACE_DECL))
5401 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005402 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005403 }
Owen Taylor3473f882001-02-23 17:55:21 +00005404 }
5405 }
5406 return(NULL);
5407}
5408
5409/**
5410 * xmlXPathNextAncestor:
5411 * @ctxt: the XPath Parser context
5412 * @cur: the current node in the traversal
5413 *
5414 * Traversal function for the "ancestor" direction
5415 * the ancestor axis contains the ancestors of the context node; the ancestors
5416 * of the context node consist of the parent of context node and the parent's
5417 * parent and so on; the nodes are ordered in reverse document order; thus the
5418 * parent is the first node on the axis, and the parent's parent is the second
5419 * node on the axis
5420 *
5421 * Returns the next element following that axis
5422 */
5423xmlNodePtr
5424xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5425 /*
5426 * the parent of an attribute or namespace node is the element
5427 * to which the attribute or namespace node is attached
5428 * !!!!!!!!!!!!!
5429 */
5430 if (cur == NULL) {
5431 if (ctxt->context->node == NULL) return(NULL);
5432 switch (ctxt->context->node->type) {
5433 case XML_ELEMENT_NODE:
5434 case XML_TEXT_NODE:
5435 case XML_CDATA_SECTION_NODE:
5436 case XML_ENTITY_REF_NODE:
5437 case XML_ENTITY_NODE:
5438 case XML_PI_NODE:
5439 case XML_COMMENT_NODE:
5440 case XML_DTD_NODE:
5441 case XML_ELEMENT_DECL:
5442 case XML_ATTRIBUTE_DECL:
5443 case XML_ENTITY_DECL:
5444 case XML_NOTATION_NODE:
5445 case XML_XINCLUDE_START:
5446 case XML_XINCLUDE_END:
5447 if (ctxt->context->node->parent == NULL)
5448 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005449 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005450 ((ctxt->context->node->parent->name[0] == ' ') ||
5451 (xmlStrEqual(ctxt->context->node->parent->name,
5452 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005453 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005454 return(ctxt->context->node->parent);
5455 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005456 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005457
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005458 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005459 }
5460 case XML_DOCUMENT_NODE:
5461 case XML_DOCUMENT_TYPE_NODE:
5462 case XML_DOCUMENT_FRAG_NODE:
5463 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005464#ifdef LIBXML_DOCB_ENABLED
5465 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005466#endif
5467 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005468 case XML_NAMESPACE_DECL: {
5469 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5470
5471 if ((ns->next != NULL) &&
5472 (ns->next->type != XML_NAMESPACE_DECL))
5473 return((xmlNodePtr) ns->next);
5474 /* Bad, how did that namespace ended-up there ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005475 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005476 }
Owen Taylor3473f882001-02-23 17:55:21 +00005477 }
5478 return(NULL);
5479 }
5480 if (cur == ctxt->context->doc->children)
5481 return((xmlNodePtr) ctxt->context->doc);
5482 if (cur == (xmlNodePtr) ctxt->context->doc)
5483 return(NULL);
5484 switch (cur->type) {
5485 case XML_ELEMENT_NODE:
5486 case XML_TEXT_NODE:
5487 case XML_CDATA_SECTION_NODE:
5488 case XML_ENTITY_REF_NODE:
5489 case XML_ENTITY_NODE:
5490 case XML_PI_NODE:
5491 case XML_COMMENT_NODE:
5492 case XML_NOTATION_NODE:
5493 case XML_DTD_NODE:
5494 case XML_ELEMENT_DECL:
5495 case XML_ATTRIBUTE_DECL:
5496 case XML_ENTITY_DECL:
5497 case XML_XINCLUDE_START:
5498 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005499 if (cur->parent == NULL)
5500 return(NULL);
5501 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005502 ((cur->parent->name[0] == ' ') ||
5503 (xmlStrEqual(cur->parent->name,
5504 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005505 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005506 return(cur->parent);
5507 case XML_ATTRIBUTE_NODE: {
5508 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5509
5510 return(att->parent);
5511 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005512 case XML_NAMESPACE_DECL: {
5513 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5514
5515 if ((ns->next != NULL) &&
5516 (ns->next->type != XML_NAMESPACE_DECL))
5517 return((xmlNodePtr) ns->next);
5518 /* Bad, how did that namespace ended-up there ? */
5519 return(NULL);
5520 }
Owen Taylor3473f882001-02-23 17:55:21 +00005521 case XML_DOCUMENT_NODE:
5522 case XML_DOCUMENT_TYPE_NODE:
5523 case XML_DOCUMENT_FRAG_NODE:
5524 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005525#ifdef LIBXML_DOCB_ENABLED
5526 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005527#endif
5528 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005529 }
5530 return(NULL);
5531}
5532
5533/**
5534 * xmlXPathNextAncestorOrSelf:
5535 * @ctxt: the XPath Parser context
5536 * @cur: the current node in the traversal
5537 *
5538 * Traversal function for the "ancestor-or-self" direction
5539 * he ancestor-or-self axis contains the context node and ancestors of
5540 * the context node in reverse document order; thus the context node is
5541 * the first node on the axis, and the context node's parent the second;
5542 * parent here is defined the same as with the parent axis.
5543 *
5544 * Returns the next element following that axis
5545 */
5546xmlNodePtr
5547xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5548 if (cur == NULL)
5549 return(ctxt->context->node);
5550 return(xmlXPathNextAncestor(ctxt, cur));
5551}
5552
5553/**
5554 * xmlXPathNextFollowingSibling:
5555 * @ctxt: the XPath Parser context
5556 * @cur: the current node in the traversal
5557 *
5558 * Traversal function for the "following-sibling" direction
5559 * The following-sibling axis contains the following siblings of the context
5560 * node in document order.
5561 *
5562 * Returns the next element following that axis
5563 */
5564xmlNodePtr
5565xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5566 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5567 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5568 return(NULL);
5569 if (cur == (xmlNodePtr) ctxt->context->doc)
5570 return(NULL);
5571 if (cur == NULL)
5572 return(ctxt->context->node->next);
5573 return(cur->next);
5574}
5575
5576/**
5577 * xmlXPathNextPrecedingSibling:
5578 * @ctxt: the XPath Parser context
5579 * @cur: the current node in the traversal
5580 *
5581 * Traversal function for the "preceding-sibling" direction
5582 * The preceding-sibling axis contains the preceding siblings of the context
5583 * node in reverse document order; the first preceding sibling is first on the
5584 * axis; the sibling preceding that node is the second on the axis and so on.
5585 *
5586 * Returns the next element following that axis
5587 */
5588xmlNodePtr
5589xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5590 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5591 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5592 return(NULL);
5593 if (cur == (xmlNodePtr) ctxt->context->doc)
5594 return(NULL);
5595 if (cur == NULL)
5596 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005597 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5598 cur = cur->prev;
5599 if (cur == NULL)
5600 return(ctxt->context->node->prev);
5601 }
Owen Taylor3473f882001-02-23 17:55:21 +00005602 return(cur->prev);
5603}
5604
5605/**
5606 * xmlXPathNextFollowing:
5607 * @ctxt: the XPath Parser context
5608 * @cur: the current node in the traversal
5609 *
5610 * Traversal function for the "following" direction
5611 * The following axis contains all nodes in the same document as the context
5612 * node that are after the context node in document order, excluding any
5613 * descendants and excluding attribute nodes and namespace nodes; the nodes
5614 * are ordered in document order
5615 *
5616 * Returns the next element following that axis
5617 */
5618xmlNodePtr
5619xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5620 if (cur != NULL && cur->children != NULL)
5621 return cur->children ;
5622 if (cur == NULL) cur = ctxt->context->node;
5623 if (cur == NULL) return(NULL) ; /* ERROR */
5624 if (cur->next != NULL) return(cur->next) ;
5625 do {
5626 cur = cur->parent;
5627 if (cur == NULL) return(NULL);
5628 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5629 if (cur->next != NULL) return(cur->next);
5630 } while (cur != NULL);
5631 return(cur);
5632}
5633
5634/*
5635 * xmlXPathIsAncestor:
5636 * @ancestor: the ancestor node
5637 * @node: the current node
5638 *
5639 * Check that @ancestor is a @node's ancestor
5640 *
5641 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5642 */
5643static int
5644xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5645 if ((ancestor == NULL) || (node == NULL)) return(0);
5646 /* nodes need to be in the same document */
5647 if (ancestor->doc != node->doc) return(0);
5648 /* avoid searching if ancestor or node is the root node */
5649 if (ancestor == (xmlNodePtr) node->doc) return(1);
5650 if (node == (xmlNodePtr) ancestor->doc) return(0);
5651 while (node->parent != NULL) {
5652 if (node->parent == ancestor)
5653 return(1);
5654 node = node->parent;
5655 }
5656 return(0);
5657}
5658
5659/**
5660 * xmlXPathNextPreceding:
5661 * @ctxt: the XPath Parser context
5662 * @cur: the current node in the traversal
5663 *
5664 * Traversal function for the "preceding" direction
5665 * the preceding axis contains all nodes in the same document as the context
5666 * node that are before the context node in document order, excluding any
5667 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5668 * ordered in reverse document order
5669 *
5670 * Returns the next element following that axis
5671 */
5672xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005673xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5674{
Owen Taylor3473f882001-02-23 17:55:21 +00005675 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005676 cur = ctxt->context->node;
5677 if (cur == NULL)
5678 return (NULL);
5679 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5680 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005681 do {
5682 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005683 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5684 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005685 }
5686
5687 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005688 if (cur == NULL)
5689 return (NULL);
5690 if (cur == ctxt->context->doc->children)
5691 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005692 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005693 return (cur);
5694}
5695
5696/**
5697 * xmlXPathNextPrecedingInternal:
5698 * @ctxt: the XPath Parser context
5699 * @cur: the current node in the traversal
5700 *
5701 * Traversal function for the "preceding" direction
5702 * the preceding axis contains all nodes in the same document as the context
5703 * node that are before the context node in document order, excluding any
5704 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5705 * ordered in reverse document order
5706 * This is a faster implementation but internal only since it requires a
5707 * state kept in the parser context: ctxt->ancestor.
5708 *
5709 * Returns the next element following that axis
5710 */
5711static xmlNodePtr
5712xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5713 xmlNodePtr cur)
5714{
5715 if (cur == NULL) {
5716 cur = ctxt->context->node;
5717 if (cur == NULL)
5718 return (NULL);
5719 ctxt->ancestor = cur->parent;
5720 }
5721 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5722 cur = cur->prev;
5723 while (cur->prev == NULL) {
5724 cur = cur->parent;
5725 if (cur == NULL)
5726 return (NULL);
5727 if (cur == ctxt->context->doc->children)
5728 return (NULL);
5729 if (cur != ctxt->ancestor)
5730 return (cur);
5731 ctxt->ancestor = cur->parent;
5732 }
5733 cur = cur->prev;
5734 while (cur->last != NULL)
5735 cur = cur->last;
5736 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005737}
5738
5739/**
5740 * xmlXPathNextNamespace:
5741 * @ctxt: the XPath Parser context
5742 * @cur: the current attribute in the traversal
5743 *
5744 * Traversal function for the "namespace" direction
5745 * the namespace axis contains the namespace nodes of the context node;
5746 * the order of nodes on this axis is implementation-defined; the axis will
5747 * be empty unless the context node is an element
5748 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005749 * We keep the XML namespace node at the end of the list.
5750 *
Owen Taylor3473f882001-02-23 17:55:21 +00005751 * Returns the next element following that axis
5752 */
5753xmlNodePtr
5754xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5755 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00005756 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005757 if (ctxt->context->tmpNsList != NULL)
5758 xmlFree(ctxt->context->tmpNsList);
5759 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005760 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005761 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005762 if (ctxt->context->tmpNsList != NULL) {
5763 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
5764 ctxt->context->tmpNsNr++;
5765 }
5766 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005767 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005768 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00005769 if (ctxt->context->tmpNsNr > 0) {
5770 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
5771 } else {
5772 if (ctxt->context->tmpNsList != NULL)
5773 xmlFree(ctxt->context->tmpNsList);
5774 ctxt->context->tmpNsList = NULL;
5775 return(NULL);
5776 }
Owen Taylor3473f882001-02-23 17:55:21 +00005777}
5778
5779/**
5780 * xmlXPathNextAttribute:
5781 * @ctxt: the XPath Parser context
5782 * @cur: the current attribute in the traversal
5783 *
5784 * Traversal function for the "attribute" direction
5785 * TODO: support DTD inherited default attributes
5786 *
5787 * Returns the next element following that axis
5788 */
5789xmlNodePtr
5790xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005791 if (ctxt->context->node == NULL)
5792 return(NULL);
5793 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5794 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005795 if (cur == NULL) {
5796 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5797 return(NULL);
5798 return((xmlNodePtr)ctxt->context->node->properties);
5799 }
5800 return((xmlNodePtr)cur->next);
5801}
5802
5803/************************************************************************
5804 * *
5805 * NodeTest Functions *
5806 * *
5807 ************************************************************************/
5808
Owen Taylor3473f882001-02-23 17:55:21 +00005809#define IS_FUNCTION 200
5810
Owen Taylor3473f882001-02-23 17:55:21 +00005811
5812/************************************************************************
5813 * *
5814 * Implicit tree core function library *
5815 * *
5816 ************************************************************************/
5817
5818/**
5819 * xmlXPathRoot:
5820 * @ctxt: the XPath Parser context
5821 *
5822 * Initialize the context to the root of the document
5823 */
5824void
5825xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5826 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5827 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5828}
5829
5830/************************************************************************
5831 * *
5832 * The explicit core function library *
5833 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5834 * *
5835 ************************************************************************/
5836
5837
5838/**
5839 * xmlXPathLastFunction:
5840 * @ctxt: the XPath Parser context
5841 * @nargs: the number of arguments
5842 *
5843 * Implement the last() XPath function
5844 * number last()
5845 * The last function returns the number of nodes in the context node list.
5846 */
5847void
5848xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5849 CHECK_ARITY(0);
5850 if (ctxt->context->contextSize >= 0) {
5851 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5852#ifdef DEBUG_EXPR
5853 xmlGenericError(xmlGenericErrorContext,
5854 "last() : %d\n", ctxt->context->contextSize);
5855#endif
5856 } else {
5857 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5858 }
5859}
5860
5861/**
5862 * xmlXPathPositionFunction:
5863 * @ctxt: the XPath Parser context
5864 * @nargs: the number of arguments
5865 *
5866 * Implement the position() XPath function
5867 * number position()
5868 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005869 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00005870 * will be equal to last().
5871 */
5872void
5873xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5874 CHECK_ARITY(0);
5875 if (ctxt->context->proximityPosition >= 0) {
5876 valuePush(ctxt,
5877 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5878#ifdef DEBUG_EXPR
5879 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5880 ctxt->context->proximityPosition);
5881#endif
5882 } else {
5883 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5884 }
5885}
5886
5887/**
5888 * xmlXPathCountFunction:
5889 * @ctxt: the XPath Parser context
5890 * @nargs: the number of arguments
5891 *
5892 * Implement the count() XPath function
5893 * number count(node-set)
5894 */
5895void
5896xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5897 xmlXPathObjectPtr cur;
5898
5899 CHECK_ARITY(1);
5900 if ((ctxt->value == NULL) ||
5901 ((ctxt->value->type != XPATH_NODESET) &&
5902 (ctxt->value->type != XPATH_XSLT_TREE)))
5903 XP_ERROR(XPATH_INVALID_TYPE);
5904 cur = valuePop(ctxt);
5905
Daniel Veillard911f49a2001-04-07 15:39:35 +00005906 if ((cur == NULL) || (cur->nodesetval == NULL))
5907 valuePush(ctxt, xmlXPathNewFloat((double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00005908 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00005909 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00005910 } else {
5911 if ((cur->nodesetval->nodeNr != 1) ||
5912 (cur->nodesetval->nodeTab == NULL)) {
5913 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5914 } else {
5915 xmlNodePtr tmp;
5916 int i = 0;
5917
5918 tmp = cur->nodesetval->nodeTab[0];
5919 if (tmp != NULL) {
5920 tmp = tmp->children;
5921 while (tmp != NULL) {
5922 tmp = tmp->next;
5923 i++;
5924 }
5925 }
5926 valuePush(ctxt, xmlXPathNewFloat((double) i));
5927 }
5928 }
Owen Taylor3473f882001-02-23 17:55:21 +00005929 xmlXPathFreeObject(cur);
5930}
5931
5932/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005933 * xmlXPathGetElementsByIds:
5934 * @doc: the document
5935 * @ids: a whitespace separated list of IDs
5936 *
5937 * Selects elements by their unique ID.
5938 *
5939 * Returns a node-set of selected elements.
5940 */
5941static xmlNodeSetPtr
5942xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5943 xmlNodeSetPtr ret;
5944 const xmlChar *cur = ids;
5945 xmlChar *ID;
5946 xmlAttrPtr attr;
5947 xmlNodePtr elem = NULL;
5948
Daniel Veillard7a985a12003-07-06 17:57:42 +00005949 if (ids == NULL) return(NULL);
5950
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005951 ret = xmlXPathNodeSetCreate(NULL);
5952
5953 while (IS_BLANK(*cur)) cur++;
5954 while (*cur != 0) {
Daniel Veillarde209b332003-03-26 21:40:13 +00005955 while ((!IS_BLANK(*cur)) && (*cur != 0))
5956 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005957
5958 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00005959 if (ID != NULL) {
5960 if (xmlValidateNCName(ID, 1) == 0) {
5961 attr = xmlGetID(doc, ID);
5962 if (attr != NULL) {
5963 if (attr->type == XML_ATTRIBUTE_NODE)
5964 elem = attr->parent;
5965 else if (attr->type == XML_ELEMENT_NODE)
5966 elem = (xmlNodePtr) attr;
5967 else
5968 elem = NULL;
5969 if (elem != NULL)
5970 xmlXPathNodeSetAdd(ret, elem);
5971 }
5972 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005973 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00005974 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005975
5976 while (IS_BLANK(*cur)) cur++;
5977 ids = cur;
5978 }
5979 return(ret);
5980}
5981
5982/**
Owen Taylor3473f882001-02-23 17:55:21 +00005983 * xmlXPathIdFunction:
5984 * @ctxt: the XPath Parser context
5985 * @nargs: the number of arguments
5986 *
5987 * Implement the id() XPath function
5988 * node-set id(object)
5989 * The id function selects elements by their unique ID
5990 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
5991 * then the result is the union of the result of applying id to the
5992 * string value of each of the nodes in the argument node-set. When the
5993 * argument to id is of any other type, the argument is converted to a
5994 * string as if by a call to the string function; the string is split
5995 * into a whitespace-separated list of tokens (whitespace is any sequence
5996 * of characters matching the production S); the result is a node-set
5997 * containing the elements in the same document as the context node that
5998 * have a unique ID equal to any of the tokens in the list.
5999 */
6000void
6001xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006002 xmlChar *tokens;
6003 xmlNodeSetPtr ret;
6004 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00006005
6006 CHECK_ARITY(1);
6007 obj = valuePop(ctxt);
6008 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00006009 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006010 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00006011 int i;
6012
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006013 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006014
Daniel Veillard911f49a2001-04-07 15:39:35 +00006015 if (obj->nodesetval != NULL) {
6016 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006017 tokens =
6018 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
6019 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
6020 ret = xmlXPathNodeSetMerge(ret, ns);
6021 xmlXPathFreeNodeSet(ns);
6022 if (tokens != NULL)
6023 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006024 }
Owen Taylor3473f882001-02-23 17:55:21 +00006025 }
6026
6027 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006028 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006029 return;
6030 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006031 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00006032
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006033 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
6034 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006035
Owen Taylor3473f882001-02-23 17:55:21 +00006036 xmlXPathFreeObject(obj);
6037 return;
6038}
6039
6040/**
6041 * xmlXPathLocalNameFunction:
6042 * @ctxt: the XPath Parser context
6043 * @nargs: the number of arguments
6044 *
6045 * Implement the local-name() XPath function
6046 * string local-name(node-set?)
6047 * The local-name function returns a string containing the local part
6048 * of the name of the node in the argument node-set that is first in
6049 * document order. If the node-set is empty or the first node has no
6050 * name, an empty string is returned. If the argument is omitted it
6051 * defaults to the context node.
6052 */
6053void
6054xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6055 xmlXPathObjectPtr cur;
6056
6057 if (nargs == 0) {
6058 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6059 nargs = 1;
6060 }
6061
6062 CHECK_ARITY(1);
6063 if ((ctxt->value == NULL) ||
6064 ((ctxt->value->type != XPATH_NODESET) &&
6065 (ctxt->value->type != XPATH_XSLT_TREE)))
6066 XP_ERROR(XPATH_INVALID_TYPE);
6067 cur = valuePop(ctxt);
6068
Daniel Veillard911f49a2001-04-07 15:39:35 +00006069 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006070 valuePush(ctxt, xmlXPathNewCString(""));
6071 } else {
6072 int i = 0; /* Should be first in document order !!!!! */
6073 switch (cur->nodesetval->nodeTab[i]->type) {
6074 case XML_ELEMENT_NODE:
6075 case XML_ATTRIBUTE_NODE:
6076 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006077 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6078 valuePush(ctxt, xmlXPathNewCString(""));
6079 else
6080 valuePush(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006081 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
6082 break;
6083 case XML_NAMESPACE_DECL:
6084 valuePush(ctxt, xmlXPathNewString(
6085 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
6086 break;
6087 default:
6088 valuePush(ctxt, xmlXPathNewCString(""));
6089 }
6090 }
6091 xmlXPathFreeObject(cur);
6092}
6093
6094/**
6095 * xmlXPathNamespaceURIFunction:
6096 * @ctxt: the XPath Parser context
6097 * @nargs: the number of arguments
6098 *
6099 * Implement the namespace-uri() XPath function
6100 * string namespace-uri(node-set?)
6101 * The namespace-uri function returns a string containing the
6102 * namespace URI of the expanded name of the node in the argument
6103 * node-set that is first in document order. If the node-set is empty,
6104 * the first node has no name, or the expanded name has no namespace
6105 * URI, an empty string is returned. If the argument is omitted it
6106 * defaults to the context node.
6107 */
6108void
6109xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6110 xmlXPathObjectPtr cur;
6111
6112 if (nargs == 0) {
6113 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6114 nargs = 1;
6115 }
6116 CHECK_ARITY(1);
6117 if ((ctxt->value == NULL) ||
6118 ((ctxt->value->type != XPATH_NODESET) &&
6119 (ctxt->value->type != XPATH_XSLT_TREE)))
6120 XP_ERROR(XPATH_INVALID_TYPE);
6121 cur = valuePop(ctxt);
6122
Daniel Veillard911f49a2001-04-07 15:39:35 +00006123 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006124 valuePush(ctxt, xmlXPathNewCString(""));
6125 } else {
6126 int i = 0; /* Should be first in document order !!!!! */
6127 switch (cur->nodesetval->nodeTab[i]->type) {
6128 case XML_ELEMENT_NODE:
6129 case XML_ATTRIBUTE_NODE:
6130 if (cur->nodesetval->nodeTab[i]->ns == NULL)
6131 valuePush(ctxt, xmlXPathNewCString(""));
6132 else
6133 valuePush(ctxt, xmlXPathNewString(
6134 cur->nodesetval->nodeTab[i]->ns->href));
6135 break;
6136 default:
6137 valuePush(ctxt, xmlXPathNewCString(""));
6138 }
6139 }
6140 xmlXPathFreeObject(cur);
6141}
6142
6143/**
6144 * xmlXPathNameFunction:
6145 * @ctxt: the XPath Parser context
6146 * @nargs: the number of arguments
6147 *
6148 * Implement the name() XPath function
6149 * string name(node-set?)
6150 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006151 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00006152 * order. The QName must represent the name with respect to the namespace
6153 * declarations in effect on the node whose name is being represented.
6154 * Typically, this will be the form in which the name occurred in the XML
6155 * source. This need not be the case if there are namespace declarations
6156 * in effect on the node that associate multiple prefixes with the same
6157 * namespace. However, an implementation may include information about
6158 * the original prefix in its representation of nodes; in this case, an
6159 * implementation can ensure that the returned string is always the same
6160 * as the QName used in the XML source. If the argument it omitted it
6161 * defaults to the context node.
6162 * Libxml keep the original prefix so the "real qualified name" used is
6163 * returned.
6164 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006165static void
Daniel Veillard04383752001-07-08 14:27:15 +00006166xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
6167{
Owen Taylor3473f882001-02-23 17:55:21 +00006168 xmlXPathObjectPtr cur;
6169
6170 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00006171 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6172 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006173 }
6174
6175 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00006176 if ((ctxt->value == NULL) ||
6177 ((ctxt->value->type != XPATH_NODESET) &&
6178 (ctxt->value->type != XPATH_XSLT_TREE)))
6179 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006180 cur = valuePop(ctxt);
6181
Daniel Veillard911f49a2001-04-07 15:39:35 +00006182 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006183 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00006184 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006185 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00006186
Daniel Veillard04383752001-07-08 14:27:15 +00006187 switch (cur->nodesetval->nodeTab[i]->type) {
6188 case XML_ELEMENT_NODE:
6189 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006190 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6191 valuePush(ctxt, xmlXPathNewCString(""));
6192 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6193 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006194 valuePush(ctxt,
Daniel Veillardc00cda82003-04-07 10:22:39 +00006195 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
Daniel Veillard04383752001-07-08 14:27:15 +00006196
Daniel Veillard652d8a92003-02-04 19:28:49 +00006197 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006198 xmlChar *fullname;
6199
6200 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
6201 cur->nodesetval->nodeTab[i]->ns->prefix,
6202 NULL, 0);
6203 if (fullname == cur->nodesetval->nodeTab[i]->name)
6204 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
6205 if (fullname == NULL) {
6206 XP_ERROR(XPATH_MEMORY_ERROR);
6207 }
6208 valuePush(ctxt, xmlXPathWrapString(fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00006209 }
6210 break;
6211 default:
6212 valuePush(ctxt,
6213 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6214 xmlXPathLocalNameFunction(ctxt, 1);
6215 }
Owen Taylor3473f882001-02-23 17:55:21 +00006216 }
6217 xmlXPathFreeObject(cur);
6218}
6219
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006220
6221/**
Owen Taylor3473f882001-02-23 17:55:21 +00006222 * xmlXPathStringFunction:
6223 * @ctxt: the XPath Parser context
6224 * @nargs: the number of arguments
6225 *
6226 * Implement the string() XPath function
6227 * string string(object?)
6228 * he string function converts an object to a string as follows:
6229 * - A node-set is converted to a string by returning the value of
6230 * the node in the node-set that is first in document order.
6231 * If the node-set is empty, an empty string is returned.
6232 * - A number is converted to a string as follows
6233 * + NaN is converted to the string NaN
6234 * + positive zero is converted to the string 0
6235 * + negative zero is converted to the string 0
6236 * + positive infinity is converted to the string Infinity
6237 * + negative infinity is converted to the string -Infinity
6238 * + if the number is an integer, the number is represented in
6239 * decimal form as a Number with no decimal point and no leading
6240 * zeros, preceded by a minus sign (-) if the number is negative
6241 * + otherwise, the number is represented in decimal form as a
6242 * Number including a decimal point with at least one digit
6243 * before the decimal point and at least one digit after the
6244 * decimal point, preceded by a minus sign (-) if the number
6245 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006246 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00006247 * before the decimal point; beyond the one required digit
6248 * after the decimal point there must be as many, but only as
6249 * many, more digits as are needed to uniquely distinguish the
6250 * number from all other IEEE 754 numeric values.
6251 * - The boolean false value is converted to the string false.
6252 * The boolean true value is converted to the string true.
6253 *
6254 * If the argument is omitted, it defaults to a node-set with the
6255 * context node as its only member.
6256 */
6257void
6258xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6259 xmlXPathObjectPtr cur;
6260
6261 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006262 valuePush(ctxt,
6263 xmlXPathWrapString(
6264 xmlXPathCastNodeToString(ctxt->context->node)));
6265 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006266 }
6267
6268 CHECK_ARITY(1);
6269 cur = valuePop(ctxt);
6270 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006271 cur = xmlXPathConvertString(cur);
6272 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006273}
6274
6275/**
6276 * xmlXPathStringLengthFunction:
6277 * @ctxt: the XPath Parser context
6278 * @nargs: the number of arguments
6279 *
6280 * Implement the string-length() XPath function
6281 * number string-length(string?)
6282 * The string-length returns the number of characters in the string
6283 * (see [3.6 Strings]). If the argument is omitted, it defaults to
6284 * the context node converted to a string, in other words the value
6285 * of the context node.
6286 */
6287void
6288xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6289 xmlXPathObjectPtr cur;
6290
6291 if (nargs == 0) {
6292 if (ctxt->context->node == NULL) {
6293 valuePush(ctxt, xmlXPathNewFloat(0));
6294 } else {
6295 xmlChar *content;
6296
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006297 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006298 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00006299 xmlFree(content);
6300 }
6301 return;
6302 }
6303 CHECK_ARITY(1);
6304 CAST_TO_STRING;
6305 CHECK_TYPE(XPATH_STRING);
6306 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006307 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00006308 xmlXPathFreeObject(cur);
6309}
6310
6311/**
6312 * xmlXPathConcatFunction:
6313 * @ctxt: the XPath Parser context
6314 * @nargs: the number of arguments
6315 *
6316 * Implement the concat() XPath function
6317 * string concat(string, string, string*)
6318 * The concat function returns the concatenation of its arguments.
6319 */
6320void
6321xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6322 xmlXPathObjectPtr cur, newobj;
6323 xmlChar *tmp;
6324
6325 if (nargs < 2) {
6326 CHECK_ARITY(2);
6327 }
6328
6329 CAST_TO_STRING;
6330 cur = valuePop(ctxt);
6331 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6332 xmlXPathFreeObject(cur);
6333 return;
6334 }
6335 nargs--;
6336
6337 while (nargs > 0) {
6338 CAST_TO_STRING;
6339 newobj = valuePop(ctxt);
6340 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6341 xmlXPathFreeObject(newobj);
6342 xmlXPathFreeObject(cur);
6343 XP_ERROR(XPATH_INVALID_TYPE);
6344 }
6345 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6346 newobj->stringval = cur->stringval;
6347 cur->stringval = tmp;
6348
6349 xmlXPathFreeObject(newobj);
6350 nargs--;
6351 }
6352 valuePush(ctxt, cur);
6353}
6354
6355/**
6356 * xmlXPathContainsFunction:
6357 * @ctxt: the XPath Parser context
6358 * @nargs: the number of arguments
6359 *
6360 * Implement the contains() XPath function
6361 * boolean contains(string, string)
6362 * The contains function returns true if the first argument string
6363 * contains the second argument string, and otherwise returns false.
6364 */
6365void
6366xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6367 xmlXPathObjectPtr hay, needle;
6368
6369 CHECK_ARITY(2);
6370 CAST_TO_STRING;
6371 CHECK_TYPE(XPATH_STRING);
6372 needle = valuePop(ctxt);
6373 CAST_TO_STRING;
6374 hay = valuePop(ctxt);
6375 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6376 xmlXPathFreeObject(hay);
6377 xmlXPathFreeObject(needle);
6378 XP_ERROR(XPATH_INVALID_TYPE);
6379 }
6380 if (xmlStrstr(hay->stringval, needle->stringval))
6381 valuePush(ctxt, xmlXPathNewBoolean(1));
6382 else
6383 valuePush(ctxt, xmlXPathNewBoolean(0));
6384 xmlXPathFreeObject(hay);
6385 xmlXPathFreeObject(needle);
6386}
6387
6388/**
6389 * xmlXPathStartsWithFunction:
6390 * @ctxt: the XPath Parser context
6391 * @nargs: the number of arguments
6392 *
6393 * Implement the starts-with() XPath function
6394 * boolean starts-with(string, string)
6395 * The starts-with function returns true if the first argument string
6396 * starts with the second argument string, and otherwise returns false.
6397 */
6398void
6399xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6400 xmlXPathObjectPtr hay, needle;
6401 int n;
6402
6403 CHECK_ARITY(2);
6404 CAST_TO_STRING;
6405 CHECK_TYPE(XPATH_STRING);
6406 needle = valuePop(ctxt);
6407 CAST_TO_STRING;
6408 hay = valuePop(ctxt);
6409 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6410 xmlXPathFreeObject(hay);
6411 xmlXPathFreeObject(needle);
6412 XP_ERROR(XPATH_INVALID_TYPE);
6413 }
6414 n = xmlStrlen(needle->stringval);
6415 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6416 valuePush(ctxt, xmlXPathNewBoolean(0));
6417 else
6418 valuePush(ctxt, xmlXPathNewBoolean(1));
6419 xmlXPathFreeObject(hay);
6420 xmlXPathFreeObject(needle);
6421}
6422
6423/**
6424 * xmlXPathSubstringFunction:
6425 * @ctxt: the XPath Parser context
6426 * @nargs: the number of arguments
6427 *
6428 * Implement the substring() XPath function
6429 * string substring(string, number, number?)
6430 * The substring function returns the substring of the first argument
6431 * starting at the position specified in the second argument with
6432 * length specified in the third argument. For example,
6433 * substring("12345",2,3) returns "234". If the third argument is not
6434 * specified, it returns the substring starting at the position specified
6435 * in the second argument and continuing to the end of the string. For
6436 * example, substring("12345",2) returns "2345". More precisely, each
6437 * character in the string (see [3.6 Strings]) is considered to have a
6438 * numeric position: the position of the first character is 1, the position
6439 * of the second character is 2 and so on. The returned substring contains
6440 * those characters for which the position of the character is greater than
6441 * or equal to the second argument and, if the third argument is specified,
6442 * less than the sum of the second and third arguments; the comparisons
6443 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6444 * - substring("12345", 1.5, 2.6) returns "234"
6445 * - substring("12345", 0, 3) returns "12"
6446 * - substring("12345", 0 div 0, 3) returns ""
6447 * - substring("12345", 1, 0 div 0) returns ""
6448 * - substring("12345", -42, 1 div 0) returns "12345"
6449 * - substring("12345", -1 div 0, 1 div 0) returns ""
6450 */
6451void
6452xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6453 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006454 double le=0, in;
6455 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006456 xmlChar *ret;
6457
Owen Taylor3473f882001-02-23 17:55:21 +00006458 if (nargs < 2) {
6459 CHECK_ARITY(2);
6460 }
6461 if (nargs > 3) {
6462 CHECK_ARITY(3);
6463 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006464 /*
6465 * take care of possible last (position) argument
6466 */
Owen Taylor3473f882001-02-23 17:55:21 +00006467 if (nargs == 3) {
6468 CAST_TO_NUMBER;
6469 CHECK_TYPE(XPATH_NUMBER);
6470 len = valuePop(ctxt);
6471 le = len->floatval;
6472 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006473 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006474
Owen Taylor3473f882001-02-23 17:55:21 +00006475 CAST_TO_NUMBER;
6476 CHECK_TYPE(XPATH_NUMBER);
6477 start = valuePop(ctxt);
6478 in = start->floatval;
6479 xmlXPathFreeObject(start);
6480 CAST_TO_STRING;
6481 CHECK_TYPE(XPATH_STRING);
6482 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006483 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006484
Daniel Veillard97ac1312001-05-30 19:14:17 +00006485 /*
6486 * If last pos not present, calculate last position
6487 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006488 if (nargs != 3) {
6489 le = (double)m;
6490 if (in < 1.0)
6491 in = 1.0;
6492 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006493
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006494 /* Need to check for the special cases where either
6495 * the index is NaN, the length is NaN, or both
6496 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00006497 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006498 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006499 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00006500 * To meet the requirements of the spec, the arguments
6501 * must be converted to integer format before
6502 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006503 *
Daniel Veillard9e412302002-06-10 15:59:44 +00006504 * First we go to integer form, rounding up
6505 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006506 */
6507 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00006508 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00006509
Daniel Veillard9e412302002-06-10 15:59:44 +00006510 if (xmlXPathIsInf(le) == 1) {
6511 l = m;
6512 if (i < 1)
6513 i = 1;
6514 }
6515 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
6516 l = 0;
6517 else {
6518 l = (int) le;
6519 if (((double)l)+0.5 <= le) l++;
6520 }
6521
6522 /* Now we normalize inidices */
6523 i -= 1;
6524 l += i;
6525 if (i < 0)
6526 i = 0;
6527 if (l > m)
6528 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00006529
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006530 /* number of chars to copy */
6531 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00006532
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006533 ret = xmlUTF8Strsub(str->stringval, i, l);
6534 }
6535 else {
6536 ret = NULL;
6537 }
6538
Owen Taylor3473f882001-02-23 17:55:21 +00006539 if (ret == NULL)
6540 valuePush(ctxt, xmlXPathNewCString(""));
6541 else {
6542 valuePush(ctxt, xmlXPathNewString(ret));
6543 xmlFree(ret);
6544 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006545
Owen Taylor3473f882001-02-23 17:55:21 +00006546 xmlXPathFreeObject(str);
6547}
6548
6549/**
6550 * xmlXPathSubstringBeforeFunction:
6551 * @ctxt: the XPath Parser context
6552 * @nargs: the number of arguments
6553 *
6554 * Implement the substring-before() XPath function
6555 * string substring-before(string, string)
6556 * The substring-before function returns the substring of the first
6557 * argument string that precedes the first occurrence of the second
6558 * argument string in the first argument string, or the empty string
6559 * if the first argument string does not contain the second argument
6560 * string. For example, substring-before("1999/04/01","/") returns 1999.
6561 */
6562void
6563xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6564 xmlXPathObjectPtr str;
6565 xmlXPathObjectPtr find;
6566 xmlBufferPtr target;
6567 const xmlChar *point;
6568 int offset;
6569
6570 CHECK_ARITY(2);
6571 CAST_TO_STRING;
6572 find = valuePop(ctxt);
6573 CAST_TO_STRING;
6574 str = valuePop(ctxt);
6575
6576 target = xmlBufferCreate();
6577 if (target) {
6578 point = xmlStrstr(str->stringval, find->stringval);
6579 if (point) {
6580 offset = (int)(point - str->stringval);
6581 xmlBufferAdd(target, str->stringval, offset);
6582 }
6583 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6584 xmlBufferFree(target);
6585 }
6586
6587 xmlXPathFreeObject(str);
6588 xmlXPathFreeObject(find);
6589}
6590
6591/**
6592 * xmlXPathSubstringAfterFunction:
6593 * @ctxt: the XPath Parser context
6594 * @nargs: the number of arguments
6595 *
6596 * Implement the substring-after() XPath function
6597 * string substring-after(string, string)
6598 * The substring-after function returns the substring of the first
6599 * argument string that follows the first occurrence of the second
6600 * argument string in the first argument string, or the empty stringi
6601 * if the first argument string does not contain the second argument
6602 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6603 * and substring-after("1999/04/01","19") returns 99/04/01.
6604 */
6605void
6606xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6607 xmlXPathObjectPtr str;
6608 xmlXPathObjectPtr find;
6609 xmlBufferPtr target;
6610 const xmlChar *point;
6611 int offset;
6612
6613 CHECK_ARITY(2);
6614 CAST_TO_STRING;
6615 find = valuePop(ctxt);
6616 CAST_TO_STRING;
6617 str = valuePop(ctxt);
6618
6619 target = xmlBufferCreate();
6620 if (target) {
6621 point = xmlStrstr(str->stringval, find->stringval);
6622 if (point) {
6623 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6624 xmlBufferAdd(target, &str->stringval[offset],
6625 xmlStrlen(str->stringval) - offset);
6626 }
6627 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6628 xmlBufferFree(target);
6629 }
6630
6631 xmlXPathFreeObject(str);
6632 xmlXPathFreeObject(find);
6633}
6634
6635/**
6636 * xmlXPathNormalizeFunction:
6637 * @ctxt: the XPath Parser context
6638 * @nargs: the number of arguments
6639 *
6640 * Implement the normalize-space() XPath function
6641 * string normalize-space(string?)
6642 * The normalize-space function returns the argument string with white
6643 * space normalized by stripping leading and trailing whitespace
6644 * and replacing sequences of whitespace characters by a single
6645 * space. Whitespace characters are the same allowed by the S production
6646 * in XML. If the argument is omitted, it defaults to the context
6647 * node converted to a string, in other words the value of the context node.
6648 */
6649void
6650xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6651 xmlXPathObjectPtr obj = NULL;
6652 xmlChar *source = NULL;
6653 xmlBufferPtr target;
6654 xmlChar blank;
6655
6656 if (nargs == 0) {
6657 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006658 valuePush(ctxt,
6659 xmlXPathWrapString(
6660 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006661 nargs = 1;
6662 }
6663
6664 CHECK_ARITY(1);
6665 CAST_TO_STRING;
6666 CHECK_TYPE(XPATH_STRING);
6667 obj = valuePop(ctxt);
6668 source = obj->stringval;
6669
6670 target = xmlBufferCreate();
6671 if (target && source) {
6672
6673 /* Skip leading whitespaces */
6674 while (IS_BLANK(*source))
6675 source++;
6676
6677 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6678 blank = 0;
6679 while (*source) {
6680 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006681 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006682 } else {
6683 if (blank) {
6684 xmlBufferAdd(target, &blank, 1);
6685 blank = 0;
6686 }
6687 xmlBufferAdd(target, source, 1);
6688 }
6689 source++;
6690 }
6691
6692 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6693 xmlBufferFree(target);
6694 }
6695 xmlXPathFreeObject(obj);
6696}
6697
6698/**
6699 * xmlXPathTranslateFunction:
6700 * @ctxt: the XPath Parser context
6701 * @nargs: the number of arguments
6702 *
6703 * Implement the translate() XPath function
6704 * string translate(string, string, string)
6705 * The translate function returns the first argument string with
6706 * occurrences of characters in the second argument string replaced
6707 * by the character at the corresponding position in the third argument
6708 * string. For example, translate("bar","abc","ABC") returns the string
6709 * BAr. If there is a character in the second argument string with no
6710 * character at a corresponding position in the third argument string
6711 * (because the second argument string is longer than the third argument
6712 * string), then occurrences of that character in the first argument
6713 * string are removed. For example, translate("--aaa--","abc-","ABC")
6714 * returns "AAA". If a character occurs more than once in second
6715 * argument string, then the first occurrence determines the replacement
6716 * character. If the third argument string is longer than the second
6717 * argument string, then excess characters are ignored.
6718 */
6719void
6720xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006721 xmlXPathObjectPtr str;
6722 xmlXPathObjectPtr from;
6723 xmlXPathObjectPtr to;
6724 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006725 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006726 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006727 xmlChar *point;
6728 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006729
Daniel Veillarde043ee12001-04-16 14:08:07 +00006730 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006731
Daniel Veillarde043ee12001-04-16 14:08:07 +00006732 CAST_TO_STRING;
6733 to = valuePop(ctxt);
6734 CAST_TO_STRING;
6735 from = valuePop(ctxt);
6736 CAST_TO_STRING;
6737 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006738
Daniel Veillarde043ee12001-04-16 14:08:07 +00006739 target = xmlBufferCreate();
6740 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006741 max = xmlUTF8Strlen(to->stringval);
6742 for (cptr = str->stringval; (ch=*cptr); ) {
6743 offset = xmlUTF8Strloc(from->stringval, cptr);
6744 if (offset >= 0) {
6745 if (offset < max) {
6746 point = xmlUTF8Strpos(to->stringval, offset);
6747 if (point)
6748 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6749 }
6750 } else
6751 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6752
6753 /* Step to next character in input */
6754 cptr++;
6755 if ( ch & 0x80 ) {
6756 /* if not simple ascii, verify proper format */
6757 if ( (ch & 0xc0) != 0xc0 ) {
6758 xmlGenericError(xmlGenericErrorContext,
6759 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6760 break;
6761 }
6762 /* then skip over remaining bytes for this char */
6763 while ( (ch <<= 1) & 0x80 )
6764 if ( (*cptr++ & 0xc0) != 0x80 ) {
6765 xmlGenericError(xmlGenericErrorContext,
6766 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6767 break;
6768 }
6769 if (ch & 0x80) /* must have had error encountered */
6770 break;
6771 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006772 }
Owen Taylor3473f882001-02-23 17:55:21 +00006773 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006774 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6775 xmlBufferFree(target);
6776 xmlXPathFreeObject(str);
6777 xmlXPathFreeObject(from);
6778 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006779}
6780
6781/**
6782 * xmlXPathBooleanFunction:
6783 * @ctxt: the XPath Parser context
6784 * @nargs: the number of arguments
6785 *
6786 * Implement the boolean() XPath function
6787 * boolean boolean(object)
6788 * he boolean function converts its argument to a boolean as follows:
6789 * - a number is true if and only if it is neither positive or
6790 * negative zero nor NaN
6791 * - a node-set is true if and only if it is non-empty
6792 * - a string is true if and only if its length is non-zero
6793 */
6794void
6795xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6796 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006797
6798 CHECK_ARITY(1);
6799 cur = valuePop(ctxt);
6800 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006801 cur = xmlXPathConvertBoolean(cur);
6802 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006803}
6804
6805/**
6806 * xmlXPathNotFunction:
6807 * @ctxt: the XPath Parser context
6808 * @nargs: the number of arguments
6809 *
6810 * Implement the not() XPath function
6811 * boolean not(boolean)
6812 * The not function returns true if its argument is false,
6813 * and false otherwise.
6814 */
6815void
6816xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6817 CHECK_ARITY(1);
6818 CAST_TO_BOOLEAN;
6819 CHECK_TYPE(XPATH_BOOLEAN);
6820 ctxt->value->boolval = ! ctxt->value->boolval;
6821}
6822
6823/**
6824 * xmlXPathTrueFunction:
6825 * @ctxt: the XPath Parser context
6826 * @nargs: the number of arguments
6827 *
6828 * Implement the true() XPath function
6829 * boolean true()
6830 */
6831void
6832xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6833 CHECK_ARITY(0);
6834 valuePush(ctxt, xmlXPathNewBoolean(1));
6835}
6836
6837/**
6838 * xmlXPathFalseFunction:
6839 * @ctxt: the XPath Parser context
6840 * @nargs: the number of arguments
6841 *
6842 * Implement the false() XPath function
6843 * boolean false()
6844 */
6845void
6846xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6847 CHECK_ARITY(0);
6848 valuePush(ctxt, xmlXPathNewBoolean(0));
6849}
6850
6851/**
6852 * xmlXPathLangFunction:
6853 * @ctxt: the XPath Parser context
6854 * @nargs: the number of arguments
6855 *
6856 * Implement the lang() XPath function
6857 * boolean lang(string)
6858 * The lang function returns true or false depending on whether the
6859 * language of the context node as specified by xml:lang attributes
6860 * is the same as or is a sublanguage of the language specified by
6861 * the argument string. The language of the context node is determined
6862 * by the value of the xml:lang attribute on the context node, or, if
6863 * the context node has no xml:lang attribute, by the value of the
6864 * xml:lang attribute on the nearest ancestor of the context node that
6865 * has an xml:lang attribute. If there is no such attribute, then lang
6866 * returns false. If there is such an attribute, then lang returns
6867 * true if the attribute value is equal to the argument ignoring case,
6868 * or if there is some suffix starting with - such that the attribute
6869 * value is equal to the argument ignoring that suffix of the attribute
6870 * value and ignoring case.
6871 */
6872void
6873xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6874 xmlXPathObjectPtr val;
6875 const xmlChar *theLang;
6876 const xmlChar *lang;
6877 int ret = 0;
6878 int i;
6879
6880 CHECK_ARITY(1);
6881 CAST_TO_STRING;
6882 CHECK_TYPE(XPATH_STRING);
6883 val = valuePop(ctxt);
6884 lang = val->stringval;
6885 theLang = xmlNodeGetLang(ctxt->context->node);
6886 if ((theLang != NULL) && (lang != NULL)) {
6887 for (i = 0;lang[i] != 0;i++)
6888 if (toupper(lang[i]) != toupper(theLang[i]))
6889 goto not_equal;
6890 ret = 1;
6891 }
6892not_equal:
6893 xmlXPathFreeObject(val);
6894 valuePush(ctxt, xmlXPathNewBoolean(ret));
6895}
6896
6897/**
6898 * xmlXPathNumberFunction:
6899 * @ctxt: the XPath Parser context
6900 * @nargs: the number of arguments
6901 *
6902 * Implement the number() XPath function
6903 * number number(object?)
6904 */
6905void
6906xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6907 xmlXPathObjectPtr cur;
6908 double res;
6909
6910 if (nargs == 0) {
6911 if (ctxt->context->node == NULL) {
6912 valuePush(ctxt, xmlXPathNewFloat(0.0));
6913 } else {
6914 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6915
6916 res = xmlXPathStringEvalNumber(content);
6917 valuePush(ctxt, xmlXPathNewFloat(res));
6918 xmlFree(content);
6919 }
6920 return;
6921 }
6922
6923 CHECK_ARITY(1);
6924 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006925 cur = xmlXPathConvertNumber(cur);
6926 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006927}
6928
6929/**
6930 * xmlXPathSumFunction:
6931 * @ctxt: the XPath Parser context
6932 * @nargs: the number of arguments
6933 *
6934 * Implement the sum() XPath function
6935 * number sum(node-set)
6936 * The sum function returns the sum of the values of the nodes in
6937 * the argument node-set.
6938 */
6939void
6940xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6941 xmlXPathObjectPtr cur;
6942 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006943 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00006944
6945 CHECK_ARITY(1);
6946 if ((ctxt->value == NULL) ||
6947 ((ctxt->value->type != XPATH_NODESET) &&
6948 (ctxt->value->type != XPATH_XSLT_TREE)))
6949 XP_ERROR(XPATH_INVALID_TYPE);
6950 cur = valuePop(ctxt);
6951
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006952 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006953 valuePush(ctxt, xmlXPathNewFloat(0.0));
6954 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006955 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
6956 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006957 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006958 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00006959 }
6960 xmlXPathFreeObject(cur);
6961}
6962
6963/**
6964 * xmlXPathFloorFunction:
6965 * @ctxt: the XPath Parser context
6966 * @nargs: the number of arguments
6967 *
6968 * Implement the floor() XPath function
6969 * number floor(number)
6970 * The floor function returns the largest (closest to positive infinity)
6971 * number that is not greater than the argument and that is an integer.
6972 */
6973void
6974xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006975 double f;
6976
Owen Taylor3473f882001-02-23 17:55:21 +00006977 CHECK_ARITY(1);
6978 CAST_TO_NUMBER;
6979 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006980
6981 f = (double)((int) ctxt->value->floatval);
6982 if (f != ctxt->value->floatval) {
6983 if (ctxt->value->floatval > 0)
6984 ctxt->value->floatval = f;
6985 else
6986 ctxt->value->floatval = f - 1;
6987 }
Owen Taylor3473f882001-02-23 17:55:21 +00006988}
6989
6990/**
6991 * xmlXPathCeilingFunction:
6992 * @ctxt: the XPath Parser context
6993 * @nargs: the number of arguments
6994 *
6995 * Implement the ceiling() XPath function
6996 * number ceiling(number)
6997 * The ceiling function returns the smallest (closest to negative infinity)
6998 * number that is not less than the argument and that is an integer.
6999 */
7000void
7001xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7002 double f;
7003
7004 CHECK_ARITY(1);
7005 CAST_TO_NUMBER;
7006 CHECK_TYPE(XPATH_NUMBER);
7007
7008#if 0
7009 ctxt->value->floatval = ceil(ctxt->value->floatval);
7010#else
7011 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007012 if (f != ctxt->value->floatval) {
7013 if (ctxt->value->floatval > 0)
7014 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007015 else {
7016 if (ctxt->value->floatval < 0 && f == 0)
7017 ctxt->value->floatval = xmlXPathNZERO;
7018 else
7019 ctxt->value->floatval = f;
7020 }
7021
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007022 }
Owen Taylor3473f882001-02-23 17:55:21 +00007023#endif
7024}
7025
7026/**
7027 * xmlXPathRoundFunction:
7028 * @ctxt: the XPath Parser context
7029 * @nargs: the number of arguments
7030 *
7031 * Implement the round() XPath function
7032 * number round(number)
7033 * The round function returns the number that is closest to the
7034 * argument and that is an integer. If there are two such numbers,
7035 * then the one that is even is returned.
7036 */
7037void
7038xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7039 double f;
7040
7041 CHECK_ARITY(1);
7042 CAST_TO_NUMBER;
7043 CHECK_TYPE(XPATH_NUMBER);
7044
Daniel Veillardcda96922001-08-21 10:56:31 +00007045 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
7046 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
7047 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007048 (ctxt->value->floatval == 0.0))
7049 return;
7050
Owen Taylor3473f882001-02-23 17:55:21 +00007051 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007052 if (ctxt->value->floatval < 0) {
7053 if (ctxt->value->floatval < f - 0.5)
7054 ctxt->value->floatval = f - 1;
7055 else
7056 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007057 if (ctxt->value->floatval == 0)
7058 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007059 } else {
7060 if (ctxt->value->floatval < f + 0.5)
7061 ctxt->value->floatval = f;
7062 else
7063 ctxt->value->floatval = f + 1;
7064 }
Owen Taylor3473f882001-02-23 17:55:21 +00007065}
7066
7067/************************************************************************
7068 * *
7069 * The Parser *
7070 * *
7071 ************************************************************************/
7072
7073/*
7074 * a couple of forward declarations since we use a recursive call based
7075 * implementation.
7076 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007077static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007078static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007079static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007080static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00007081static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
7082 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00007083
7084/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00007085 * xmlXPathCurrentChar:
7086 * @ctxt: the XPath parser context
7087 * @cur: pointer to the beginning of the char
7088 * @len: pointer to the length of the char read
7089 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007090 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00007091 * bytes in the input buffer.
7092 *
Daniel Veillard60087f32001-10-10 09:45:09 +00007093 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00007094 */
7095
7096static int
7097xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
7098 unsigned char c;
7099 unsigned int val;
7100 const xmlChar *cur;
7101
7102 if (ctxt == NULL)
7103 return(0);
7104 cur = ctxt->cur;
7105
7106 /*
7107 * We are supposed to handle UTF8, check it's valid
7108 * From rfc2044: encoding of the Unicode values on UTF-8:
7109 *
7110 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
7111 * 0000 0000-0000 007F 0xxxxxxx
7112 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
7113 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
7114 *
7115 * Check for the 0x110000 limit too
7116 */
7117 c = *cur;
7118 if (c & 0x80) {
7119 if ((cur[1] & 0xc0) != 0x80)
7120 goto encoding_error;
7121 if ((c & 0xe0) == 0xe0) {
7122
7123 if ((cur[2] & 0xc0) != 0x80)
7124 goto encoding_error;
7125 if ((c & 0xf0) == 0xf0) {
7126 if (((c & 0xf8) != 0xf0) ||
7127 ((cur[3] & 0xc0) != 0x80))
7128 goto encoding_error;
7129 /* 4-byte code */
7130 *len = 4;
7131 val = (cur[0] & 0x7) << 18;
7132 val |= (cur[1] & 0x3f) << 12;
7133 val |= (cur[2] & 0x3f) << 6;
7134 val |= cur[3] & 0x3f;
7135 } else {
7136 /* 3-byte code */
7137 *len = 3;
7138 val = (cur[0] & 0xf) << 12;
7139 val |= (cur[1] & 0x3f) << 6;
7140 val |= cur[2] & 0x3f;
7141 }
7142 } else {
7143 /* 2-byte code */
7144 *len = 2;
7145 val = (cur[0] & 0x1f) << 6;
7146 val |= cur[1] & 0x3f;
7147 }
7148 if (!IS_CHAR(val)) {
7149 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
7150 }
7151 return(val);
7152 } else {
7153 /* 1-byte code */
7154 *len = 1;
7155 return((int) *cur);
7156 }
7157encoding_error:
7158 /*
7159 * If we detect an UTF8 error that probably mean that the
7160 * input encoding didn't get properly advertized in the
7161 * declaration header. Report the error and switch the encoding
7162 * to ISO-Latin-1 (if you don't like this policy, just declare the
7163 * encoding !)
7164 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00007165 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00007166 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007167}
7168
7169/**
Owen Taylor3473f882001-02-23 17:55:21 +00007170 * xmlXPathParseNCName:
7171 * @ctxt: the XPath Parser context
7172 *
7173 * parse an XML namespace non qualified name.
7174 *
7175 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7176 *
7177 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7178 * CombiningChar | Extender
7179 *
7180 * Returns the namespace name or NULL
7181 */
7182
7183xmlChar *
7184xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00007185 const xmlChar *in;
7186 xmlChar *ret;
7187 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007188
Daniel Veillard2156a562001-04-28 12:24:34 +00007189 /*
7190 * Accelerator for simple ASCII names
7191 */
7192 in = ctxt->cur;
7193 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7194 ((*in >= 0x41) && (*in <= 0x5A)) ||
7195 (*in == '_')) {
7196 in++;
7197 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7198 ((*in >= 0x41) && (*in <= 0x5A)) ||
7199 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00007200 (*in == '_') || (*in == '.') ||
7201 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00007202 in++;
7203 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7204 (*in == '[') || (*in == ']') || (*in == ':') ||
7205 (*in == '@') || (*in == '*')) {
7206 count = in - ctxt->cur;
7207 if (count == 0)
7208 return(NULL);
7209 ret = xmlStrndup(ctxt->cur, count);
7210 ctxt->cur = in;
7211 return(ret);
7212 }
7213 }
7214 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00007215}
7216
Daniel Veillard2156a562001-04-28 12:24:34 +00007217
Owen Taylor3473f882001-02-23 17:55:21 +00007218/**
7219 * xmlXPathParseQName:
7220 * @ctxt: the XPath Parser context
7221 * @prefix: a xmlChar **
7222 *
7223 * parse an XML qualified name
7224 *
7225 * [NS 5] QName ::= (Prefix ':')? LocalPart
7226 *
7227 * [NS 6] Prefix ::= NCName
7228 *
7229 * [NS 7] LocalPart ::= NCName
7230 *
7231 * Returns the function returns the local part, and prefix is updated
7232 * to get the Prefix if any.
7233 */
7234
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007235static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007236xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7237 xmlChar *ret = NULL;
7238
7239 *prefix = NULL;
7240 ret = xmlXPathParseNCName(ctxt);
7241 if (CUR == ':') {
7242 *prefix = ret;
7243 NEXT;
7244 ret = xmlXPathParseNCName(ctxt);
7245 }
7246 return(ret);
7247}
7248
7249/**
7250 * xmlXPathParseName:
7251 * @ctxt: the XPath Parser context
7252 *
7253 * parse an XML name
7254 *
7255 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7256 * CombiningChar | Extender
7257 *
7258 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7259 *
7260 * Returns the namespace name or NULL
7261 */
7262
7263xmlChar *
7264xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007265 const xmlChar *in;
7266 xmlChar *ret;
7267 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007268
Daniel Veillard61d80a22001-04-27 17:13:01 +00007269 /*
7270 * Accelerator for simple ASCII names
7271 */
7272 in = ctxt->cur;
7273 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7274 ((*in >= 0x41) && (*in <= 0x5A)) ||
7275 (*in == '_') || (*in == ':')) {
7276 in++;
7277 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7278 ((*in >= 0x41) && (*in <= 0x5A)) ||
7279 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00007280 (*in == '_') || (*in == '-') ||
7281 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00007282 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007283 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007284 count = in - ctxt->cur;
7285 ret = xmlStrndup(ctxt->cur, count);
7286 ctxt->cur = in;
7287 return(ret);
7288 }
7289 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007290 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00007291}
7292
Daniel Veillard61d80a22001-04-27 17:13:01 +00007293static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00007294xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007295 xmlChar buf[XML_MAX_NAMELEN + 5];
7296 int len = 0, l;
7297 int c;
7298
7299 /*
7300 * Handler for more complex cases
7301 */
7302 c = CUR_CHAR(l);
7303 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00007304 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7305 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00007306 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00007307 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007308 return(NULL);
7309 }
7310
7311 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7312 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7313 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007314 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007315 (IS_COMBINING(c)) ||
7316 (IS_EXTENDER(c)))) {
7317 COPY_BUF(l,buf,len,c);
7318 NEXTL(l);
7319 c = CUR_CHAR(l);
7320 if (len >= XML_MAX_NAMELEN) {
7321 /*
7322 * Okay someone managed to make a huge name, so he's ready to pay
7323 * for the processing speed.
7324 */
7325 xmlChar *buffer;
7326 int max = len * 2;
7327
Daniel Veillard3c908dc2003-04-19 00:07:51 +00007328 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007329 if (buffer == NULL) {
7330 XP_ERROR0(XPATH_MEMORY_ERROR);
7331 }
7332 memcpy(buffer, buf, len);
7333 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7334 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007335 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007336 (IS_COMBINING(c)) ||
7337 (IS_EXTENDER(c))) {
7338 if (len + 10 > max) {
7339 max *= 2;
7340 buffer = (xmlChar *) xmlRealloc(buffer,
7341 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007342 if (buffer == NULL) {
7343 XP_ERROR0(XPATH_MEMORY_ERROR);
7344 }
7345 }
7346 COPY_BUF(l,buffer,len,c);
7347 NEXTL(l);
7348 c = CUR_CHAR(l);
7349 }
7350 buffer[len] = 0;
7351 return(buffer);
7352 }
7353 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007354 if (len == 0)
7355 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007356 return(xmlStrndup(buf, len));
7357}
Daniel Veillard3cd72402002-05-13 10:33:30 +00007358
7359#define MAX_FRAC 20
7360
7361static double my_pow10[MAX_FRAC] = {
7362 1.0, 10.0, 100.0, 1000.0, 10000.0,
7363 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7364 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7365 100000000000000.0,
7366 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
7367 1000000000000000000.0, 10000000000000000000.0
7368};
7369
Owen Taylor3473f882001-02-23 17:55:21 +00007370/**
7371 * xmlXPathStringEvalNumber:
7372 * @str: A string to scan
7373 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00007374 * [30a] Float ::= Number ('e' Digits?)?
7375 *
Owen Taylor3473f882001-02-23 17:55:21 +00007376 * [30] Number ::= Digits ('.' Digits?)?
7377 * | '.' Digits
7378 * [31] Digits ::= [0-9]+
7379 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007380 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00007381 * In complement of the Number expression, this function also handles
7382 * negative values : '-' Number.
7383 *
7384 * Returns the double value.
7385 */
7386double
7387xmlXPathStringEvalNumber(const xmlChar *str) {
7388 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00007389 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007390 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007391 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007392 int exponent = 0;
7393 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007394#ifdef __GNUC__
7395 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007396 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007397#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00007398 if (cur == NULL) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00007399 while (IS_BLANK(*cur)) cur++;
7400 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7401 return(xmlXPathNAN);
7402 }
7403 if (*cur == '-') {
7404 isneg = 1;
7405 cur++;
7406 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007407
7408#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007409 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007410 * tmp/temp is a workaround against a gcc compiler bug
7411 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007412 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007413 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007414 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007415 ret = ret * 10;
7416 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00007417 ok = 1;
7418 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00007419 temp = (double) tmp;
7420 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007421 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007422#else
Daniel Veillard7b416132002-03-07 08:36:03 +00007423 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007424 while ((*cur >= '0') && (*cur <= '9')) {
7425 ret = ret * 10 + (*cur - '0');
7426 ok = 1;
7427 cur++;
7428 }
7429#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007430
Owen Taylor3473f882001-02-23 17:55:21 +00007431 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007432 int v, frac = 0;
7433 double fraction = 0;
7434
Owen Taylor3473f882001-02-23 17:55:21 +00007435 cur++;
7436 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7437 return(xmlXPathNAN);
7438 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007439 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
7440 v = (*cur - '0');
7441 fraction = fraction * 10 + v;
7442 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007443 cur++;
7444 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007445 fraction /= my_pow10[frac];
7446 ret = ret + fraction;
7447 while ((*cur >= '0') && (*cur <= '9'))
7448 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007449 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007450 if ((*cur == 'e') || (*cur == 'E')) {
7451 cur++;
7452 if (*cur == '-') {
7453 is_exponent_negative = 1;
7454 cur++;
7455 }
7456 while ((*cur >= '0') && (*cur <= '9')) {
7457 exponent = exponent * 10 + (*cur - '0');
7458 cur++;
7459 }
7460 }
Owen Taylor3473f882001-02-23 17:55:21 +00007461 while (IS_BLANK(*cur)) cur++;
7462 if (*cur != 0) return(xmlXPathNAN);
7463 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007464 if (is_exponent_negative) exponent = -exponent;
7465 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007466 return(ret);
7467}
7468
7469/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007470 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007471 * @ctxt: the XPath Parser context
7472 *
7473 * [30] Number ::= Digits ('.' Digits?)?
7474 * | '.' Digits
7475 * [31] Digits ::= [0-9]+
7476 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007477 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007478 *
7479 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007480static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007481xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7482{
Owen Taylor3473f882001-02-23 17:55:21 +00007483 double ret = 0.0;
7484 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007485 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007486 int exponent = 0;
7487 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007488#ifdef __GNUC__
7489 unsigned long tmp = 0;
7490 double temp;
7491#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007492
7493 CHECK_ERROR;
7494 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7495 XP_ERROR(XPATH_NUMBER_ERROR);
7496 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007497#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007498 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007499 * tmp/temp is a workaround against a gcc compiler bug
7500 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007501 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007502 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007503 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007504 ret = ret * 10;
7505 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007506 ok = 1;
7507 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007508 temp = (double) tmp;
7509 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007510 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007511#else
7512 ret = 0;
7513 while ((CUR >= '0') && (CUR <= '9')) {
7514 ret = ret * 10 + (CUR - '0');
7515 ok = 1;
7516 NEXT;
7517 }
7518#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007519 if (CUR == '.') {
7520 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007521 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7522 XP_ERROR(XPATH_NUMBER_ERROR);
7523 }
7524 while ((CUR >= '0') && (CUR <= '9')) {
7525 mult /= 10;
7526 ret = ret + (CUR - '0') * mult;
7527 NEXT;
7528 }
Owen Taylor3473f882001-02-23 17:55:21 +00007529 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007530 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007531 NEXT;
7532 if (CUR == '-') {
7533 is_exponent_negative = 1;
7534 NEXT;
7535 }
7536 while ((CUR >= '0') && (CUR <= '9')) {
7537 exponent = exponent * 10 + (CUR - '0');
7538 NEXT;
7539 }
7540 if (is_exponent_negative)
7541 exponent = -exponent;
7542 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007543 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007544 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007545 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007546}
7547
7548/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007549 * xmlXPathParseLiteral:
7550 * @ctxt: the XPath Parser context
7551 *
7552 * Parse a Literal
7553 *
7554 * [29] Literal ::= '"' [^"]* '"'
7555 * | "'" [^']* "'"
7556 *
7557 * Returns the value found or NULL in case of error
7558 */
7559static xmlChar *
7560xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7561 const xmlChar *q;
7562 xmlChar *ret = NULL;
7563
7564 if (CUR == '"') {
7565 NEXT;
7566 q = CUR_PTR;
Daniel Veillard34ba3872003-07-15 13:34:05 +00007567 while ((IS_CHAR((unsigned int) CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007568 NEXT;
Daniel Veillard34ba3872003-07-15 13:34:05 +00007569 if (!IS_CHAR((unsigned int) CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007570 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7571 } else {
7572 ret = xmlStrndup(q, CUR_PTR - q);
7573 NEXT;
7574 }
7575 } else if (CUR == '\'') {
7576 NEXT;
7577 q = CUR_PTR;
Daniel Veillard34ba3872003-07-15 13:34:05 +00007578 while ((IS_CHAR((unsigned int) CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007579 NEXT;
Daniel Veillard34ba3872003-07-15 13:34:05 +00007580 if (!IS_CHAR((unsigned int) CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007581 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7582 } else {
7583 ret = xmlStrndup(q, CUR_PTR - q);
7584 NEXT;
7585 }
7586 } else {
7587 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7588 }
7589 return(ret);
7590}
7591
7592/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007593 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007594 * @ctxt: the XPath Parser context
7595 *
7596 * Parse a Literal and push it on the stack.
7597 *
7598 * [29] Literal ::= '"' [^"]* '"'
7599 * | "'" [^']* "'"
7600 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007601 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007602 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007603static void
7604xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007605 const xmlChar *q;
7606 xmlChar *ret = NULL;
7607
7608 if (CUR == '"') {
7609 NEXT;
7610 q = CUR_PTR;
Daniel Veillard34ba3872003-07-15 13:34:05 +00007611 while ((IS_CHAR((unsigned int) CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +00007612 NEXT;
Daniel Veillard34ba3872003-07-15 13:34:05 +00007613 if (!IS_CHAR((unsigned int) CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007614 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7615 } else {
7616 ret = xmlStrndup(q, CUR_PTR - q);
7617 NEXT;
7618 }
7619 } else if (CUR == '\'') {
7620 NEXT;
7621 q = CUR_PTR;
Daniel Veillard34ba3872003-07-15 13:34:05 +00007622 while ((IS_CHAR((unsigned int) CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +00007623 NEXT;
Daniel Veillard34ba3872003-07-15 13:34:05 +00007624 if (!IS_CHAR((unsigned int) CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007625 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7626 } else {
7627 ret = xmlStrndup(q, CUR_PTR - q);
7628 NEXT;
7629 }
7630 } else {
7631 XP_ERROR(XPATH_START_LITERAL_ERROR);
7632 }
7633 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007634 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7635 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007636 xmlFree(ret);
7637}
7638
7639/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007640 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007641 * @ctxt: the XPath Parser context
7642 *
7643 * Parse a VariableReference, evaluate it and push it on the stack.
7644 *
7645 * The variable bindings consist of a mapping from variable names
7646 * to variable values. The value of a variable is an object, which
7647 * of any of the types that are possible for the value of an expression,
7648 * and may also be of additional types not specified here.
7649 *
7650 * Early evaluation is possible since:
7651 * The variable bindings [...] used to evaluate a subexpression are
7652 * always the same as those used to evaluate the containing expression.
7653 *
7654 * [36] VariableReference ::= '$' QName
7655 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007656static void
7657xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007658 xmlChar *name;
7659 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007660
7661 SKIP_BLANKS;
7662 if (CUR != '$') {
7663 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7664 }
7665 NEXT;
7666 name = xmlXPathParseQName(ctxt, &prefix);
7667 if (name == NULL) {
7668 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7669 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007670 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007671 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7672 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007673 SKIP_BLANKS;
7674}
7675
7676/**
7677 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +00007678 * @name: a name string
7679 *
7680 * Is the name given a NodeType one.
7681 *
7682 * [38] NodeType ::= 'comment'
7683 * | 'text'
7684 * | 'processing-instruction'
7685 * | 'node'
7686 *
7687 * Returns 1 if true 0 otherwise
7688 */
7689int
7690xmlXPathIsNodeType(const xmlChar *name) {
7691 if (name == NULL)
7692 return(0);
7693
Daniel Veillard1971ee22002-01-31 20:29:19 +00007694 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007695 return(1);
7696 if (xmlStrEqual(name, BAD_CAST "text"))
7697 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007698 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007699 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007700 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007701 return(1);
7702 return(0);
7703}
7704
7705/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007706 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007707 * @ctxt: the XPath Parser context
7708 *
7709 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7710 * [17] Argument ::= Expr
7711 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007712 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007713 * pushed on the stack
7714 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007715static void
7716xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007717 xmlChar *name;
7718 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007719 int nbargs = 0;
7720
7721 name = xmlXPathParseQName(ctxt, &prefix);
7722 if (name == NULL) {
7723 XP_ERROR(XPATH_EXPR_ERROR);
7724 }
7725 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007726#ifdef DEBUG_EXPR
7727 if (prefix == NULL)
7728 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7729 name);
7730 else
7731 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7732 prefix, name);
7733#endif
7734
Owen Taylor3473f882001-02-23 17:55:21 +00007735 if (CUR != '(') {
7736 XP_ERROR(XPATH_EXPR_ERROR);
7737 }
7738 NEXT;
7739 SKIP_BLANKS;
7740
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007741 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +00007742 if (CUR != ')') {
7743 while (CUR != 0) {
7744 int op1 = ctxt->comp->last;
7745 ctxt->comp->last = -1;
7746 xmlXPathCompileExpr(ctxt);
7747 CHECK_ERROR;
7748 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
7749 nbargs++;
7750 if (CUR == ')') break;
7751 if (CUR != ',') {
7752 XP_ERROR(XPATH_EXPR_ERROR);
7753 }
7754 NEXT;
7755 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007756 }
Owen Taylor3473f882001-02-23 17:55:21 +00007757 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007758 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7759 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007760 NEXT;
7761 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007762}
7763
7764/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007765 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007766 * @ctxt: the XPath Parser context
7767 *
7768 * [15] PrimaryExpr ::= VariableReference
7769 * | '(' Expr ')'
7770 * | Literal
7771 * | Number
7772 * | FunctionCall
7773 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007774 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007775 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007776static void
7777xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007778 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007779 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007780 else if (CUR == '(') {
7781 NEXT;
7782 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007783 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007784 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00007785 if (CUR != ')') {
7786 XP_ERROR(XPATH_EXPR_ERROR);
7787 }
7788 NEXT;
7789 SKIP_BLANKS;
Daniel Veillard01917aa2002-04-10 11:30:41 +00007790 } else if (IS_DIGIT(CUR) || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007791 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007792 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007793 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007794 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007795 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007796 }
7797 SKIP_BLANKS;
7798}
7799
7800/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007801 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007802 * @ctxt: the XPath Parser context
7803 *
7804 * [20] FilterExpr ::= PrimaryExpr
7805 * | FilterExpr Predicate
7806 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007807 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007808 * Square brackets are used to filter expressions in the same way that
7809 * they are used in location paths. It is an error if the expression to
7810 * be filtered does not evaluate to a node-set. The context node list
7811 * used for evaluating the expression in square brackets is the node-set
7812 * to be filtered listed in document order.
7813 */
7814
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007815static void
7816xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
7817 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007818 CHECK_ERROR;
7819 SKIP_BLANKS;
7820
7821 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007822 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00007823 SKIP_BLANKS;
7824 }
7825
7826
7827}
7828
7829/**
7830 * xmlXPathScanName:
7831 * @ctxt: the XPath Parser context
7832 *
7833 * Trickery: parse an XML name but without consuming the input flow
7834 * Needed to avoid insanity in the parser state.
7835 *
7836 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7837 * CombiningChar | Extender
7838 *
7839 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7840 *
7841 * [6] Names ::= Name (S Name)*
7842 *
7843 * Returns the Name parsed or NULL
7844 */
7845
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007846static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007847xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7848 xmlChar buf[XML_MAX_NAMELEN];
7849 int len = 0;
7850
7851 SKIP_BLANKS;
7852 if (!IS_LETTER(CUR) && (CUR != '_') &&
7853 (CUR != ':')) {
7854 return(NULL);
7855 }
7856
7857 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7858 (NXT(len) == '.') || (NXT(len) == '-') ||
7859 (NXT(len) == '_') || (NXT(len) == ':') ||
7860 (IS_COMBINING(NXT(len))) ||
7861 (IS_EXTENDER(NXT(len)))) {
7862 buf[len] = NXT(len);
7863 len++;
7864 if (len >= XML_MAX_NAMELEN) {
7865 xmlGenericError(xmlGenericErrorContext,
7866 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
7867 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7868 (NXT(len) == '.') || (NXT(len) == '-') ||
7869 (NXT(len) == '_') || (NXT(len) == ':') ||
7870 (IS_COMBINING(NXT(len))) ||
7871 (IS_EXTENDER(NXT(len))))
7872 len++;
7873 break;
7874 }
7875 }
7876 return(xmlStrndup(buf, len));
7877}
7878
7879/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007880 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007881 * @ctxt: the XPath Parser context
7882 *
7883 * [19] PathExpr ::= LocationPath
7884 * | FilterExpr
7885 * | FilterExpr '/' RelativeLocationPath
7886 * | FilterExpr '//' RelativeLocationPath
7887 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007888 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007889 * The / operator and // operators combine an arbitrary expression
7890 * and a relative location path. It is an error if the expression
7891 * does not evaluate to a node-set.
7892 * The / operator does composition in the same way as when / is
7893 * used in a location path. As in location paths, // is short for
7894 * /descendant-or-self::node()/.
7895 */
7896
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007897static void
7898xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007899 int lc = 1; /* Should we branch to LocationPath ? */
7900 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7901
7902 SKIP_BLANKS;
7903 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
Daniel Veillard01917aa2002-04-10 11:30:41 +00007904 (CUR == '\'') || (CUR == '"') || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00007905 lc = 0;
7906 } else if (CUR == '*') {
7907 /* relative or absolute location path */
7908 lc = 1;
7909 } else if (CUR == '/') {
7910 /* relative or absolute location path */
7911 lc = 1;
7912 } else if (CUR == '@') {
7913 /* relative abbreviated attribute location path */
7914 lc = 1;
7915 } else if (CUR == '.') {
7916 /* relative abbreviated attribute location path */
7917 lc = 1;
7918 } else {
7919 /*
7920 * Problem is finding if we have a name here whether it's:
7921 * - a nodetype
7922 * - a function call in which case it's followed by '('
7923 * - an axis in which case it's followed by ':'
7924 * - a element name
7925 * We do an a priori analysis here rather than having to
7926 * maintain parsed token content through the recursive function
7927 * calls. This looks uglier but makes the code quite easier to
7928 * read/write/debug.
7929 */
7930 SKIP_BLANKS;
7931 name = xmlXPathScanName(ctxt);
7932 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7933#ifdef DEBUG_STEP
7934 xmlGenericError(xmlGenericErrorContext,
7935 "PathExpr: Axis\n");
7936#endif
7937 lc = 1;
7938 xmlFree(name);
7939 } else if (name != NULL) {
7940 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +00007941
7942
7943 while (NXT(len) != 0) {
7944 if (NXT(len) == '/') {
7945 /* element name */
7946#ifdef DEBUG_STEP
7947 xmlGenericError(xmlGenericErrorContext,
7948 "PathExpr: AbbrRelLocation\n");
7949#endif
7950 lc = 1;
7951 break;
7952 } else if (IS_BLANK(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +00007953 /* ignore blanks */
7954 ;
Owen Taylor3473f882001-02-23 17:55:21 +00007955 } else if (NXT(len) == ':') {
7956#ifdef DEBUG_STEP
7957 xmlGenericError(xmlGenericErrorContext,
7958 "PathExpr: AbbrRelLocation\n");
7959#endif
7960 lc = 1;
7961 break;
7962 } else if ((NXT(len) == '(')) {
7963 /* Note Type or Function */
7964 if (xmlXPathIsNodeType(name)) {
7965#ifdef DEBUG_STEP
7966 xmlGenericError(xmlGenericErrorContext,
7967 "PathExpr: Type search\n");
7968#endif
7969 lc = 1;
7970 } else {
7971#ifdef DEBUG_STEP
7972 xmlGenericError(xmlGenericErrorContext,
7973 "PathExpr: function call\n");
7974#endif
7975 lc = 0;
7976 }
7977 break;
7978 } else if ((NXT(len) == '[')) {
7979 /* element name */
7980#ifdef DEBUG_STEP
7981 xmlGenericError(xmlGenericErrorContext,
7982 "PathExpr: AbbrRelLocation\n");
7983#endif
7984 lc = 1;
7985 break;
7986 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
7987 (NXT(len) == '=')) {
7988 lc = 1;
7989 break;
7990 } else {
7991 lc = 1;
7992 break;
7993 }
7994 len++;
7995 }
7996 if (NXT(len) == 0) {
7997#ifdef DEBUG_STEP
7998 xmlGenericError(xmlGenericErrorContext,
7999 "PathExpr: AbbrRelLocation\n");
8000#endif
8001 /* element name */
8002 lc = 1;
8003 }
8004 xmlFree(name);
8005 } else {
8006 /* make sure all cases are covered explicitely */
8007 XP_ERROR(XPATH_EXPR_ERROR);
8008 }
8009 }
8010
8011 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008012 if (CUR == '/') {
8013 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8014 } else {
8015 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008016 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008017 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008018 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008019 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008020 CHECK_ERROR;
8021 if ((CUR == '/') && (NXT(1) == '/')) {
8022 SKIP(2);
8023 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008024
8025 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8026 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8027 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
8028
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008029 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008030 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008031 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008032 }
8033 }
8034 SKIP_BLANKS;
8035}
8036
8037/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008038 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008039 * @ctxt: the XPath Parser context
8040 *
8041 * [18] UnionExpr ::= PathExpr
8042 * | UnionExpr '|' PathExpr
8043 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008044 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008045 */
8046
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008047static void
8048xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8049 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008050 CHECK_ERROR;
8051 SKIP_BLANKS;
8052 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008053 int op1 = ctxt->comp->last;
8054 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008055
8056 NEXT;
8057 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008058 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008059
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008060 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8061
Owen Taylor3473f882001-02-23 17:55:21 +00008062 SKIP_BLANKS;
8063 }
Owen Taylor3473f882001-02-23 17:55:21 +00008064}
8065
8066/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008067 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008068 * @ctxt: the XPath Parser context
8069 *
8070 * [27] UnaryExpr ::= UnionExpr
8071 * | '-' UnaryExpr
8072 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008073 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008074 */
8075
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008076static void
8077xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008078 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008079 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008080
8081 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00008082 while (CUR == '-') {
8083 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008084 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008085 NEXT;
8086 SKIP_BLANKS;
8087 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008088
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008089 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008090 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008091 if (found) {
8092 if (minus)
8093 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8094 else
8095 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008096 }
8097}
8098
8099/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008100 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008101 * @ctxt: the XPath Parser context
8102 *
8103 * [26] MultiplicativeExpr ::= UnaryExpr
8104 * | MultiplicativeExpr MultiplyOperator UnaryExpr
8105 * | MultiplicativeExpr 'div' UnaryExpr
8106 * | MultiplicativeExpr 'mod' UnaryExpr
8107 * [34] MultiplyOperator ::= '*'
8108 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008109 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008110 */
8111
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008112static void
8113xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8114 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008115 CHECK_ERROR;
8116 SKIP_BLANKS;
8117 while ((CUR == '*') ||
8118 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8119 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8120 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008121 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008122
8123 if (CUR == '*') {
8124 op = 0;
8125 NEXT;
8126 } else if (CUR == 'd') {
8127 op = 1;
8128 SKIP(3);
8129 } else if (CUR == 'm') {
8130 op = 2;
8131 SKIP(3);
8132 }
8133 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008134 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008135 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008136 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008137 SKIP_BLANKS;
8138 }
8139}
8140
8141/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008142 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008143 * @ctxt: the XPath Parser context
8144 *
8145 * [25] AdditiveExpr ::= MultiplicativeExpr
8146 * | AdditiveExpr '+' MultiplicativeExpr
8147 * | AdditiveExpr '-' MultiplicativeExpr
8148 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008149 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008150 */
8151
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008152static void
8153xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008154
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008155 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008156 CHECK_ERROR;
8157 SKIP_BLANKS;
8158 while ((CUR == '+') || (CUR == '-')) {
8159 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008160 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008161
8162 if (CUR == '+') plus = 1;
8163 else plus = 0;
8164 NEXT;
8165 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008166 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008167 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008168 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008169 SKIP_BLANKS;
8170 }
8171}
8172
8173/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008174 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008175 * @ctxt: the XPath Parser context
8176 *
8177 * [24] RelationalExpr ::= AdditiveExpr
8178 * | RelationalExpr '<' AdditiveExpr
8179 * | RelationalExpr '>' AdditiveExpr
8180 * | RelationalExpr '<=' AdditiveExpr
8181 * | RelationalExpr '>=' AdditiveExpr
8182 *
8183 * A <= B > C is allowed ? Answer from James, yes with
8184 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8185 * which is basically what got implemented.
8186 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008187 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00008188 * on the stack
8189 */
8190
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008191static void
8192xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8193 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008194 CHECK_ERROR;
8195 SKIP_BLANKS;
8196 while ((CUR == '<') ||
8197 (CUR == '>') ||
8198 ((CUR == '<') && (NXT(1) == '=')) ||
8199 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008200 int inf, strict;
8201 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008202
8203 if (CUR == '<') inf = 1;
8204 else inf = 0;
8205 if (NXT(1) == '=') strict = 0;
8206 else strict = 1;
8207 NEXT;
8208 if (!strict) NEXT;
8209 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008210 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008211 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008212 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00008213 SKIP_BLANKS;
8214 }
8215}
8216
8217/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008218 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008219 * @ctxt: the XPath Parser context
8220 *
8221 * [23] EqualityExpr ::= RelationalExpr
8222 * | EqualityExpr '=' RelationalExpr
8223 * | EqualityExpr '!=' RelationalExpr
8224 *
8225 * A != B != C is allowed ? Answer from James, yes with
8226 * (RelationalExpr = RelationalExpr) = RelationalExpr
8227 * (RelationalExpr != RelationalExpr) != RelationalExpr
8228 * which is basically what got implemented.
8229 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008230 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008231 *
8232 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008233static void
8234xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8235 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008236 CHECK_ERROR;
8237 SKIP_BLANKS;
8238 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008239 int eq;
8240 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008241
8242 if (CUR == '=') eq = 1;
8243 else eq = 0;
8244 NEXT;
8245 if (!eq) NEXT;
8246 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008247 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008248 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008249 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008250 SKIP_BLANKS;
8251 }
8252}
8253
8254/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008255 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008256 * @ctxt: the XPath Parser context
8257 *
8258 * [22] AndExpr ::= EqualityExpr
8259 * | AndExpr 'and' EqualityExpr
8260 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008261 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008262 *
8263 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008264static void
8265xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8266 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008267 CHECK_ERROR;
8268 SKIP_BLANKS;
8269 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008270 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008271 SKIP(3);
8272 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008273 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008274 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008275 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008276 SKIP_BLANKS;
8277 }
8278}
8279
8280/**
Daniel Veillard591b4be2003-02-09 23:33:36 +00008281 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008282 * @ctxt: the XPath Parser context
8283 *
8284 * [14] Expr ::= OrExpr
8285 * [21] OrExpr ::= AndExpr
8286 * | OrExpr 'or' AndExpr
8287 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008288 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00008289 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008290static void
8291xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8292 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008293 CHECK_ERROR;
8294 SKIP_BLANKS;
8295 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008296 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008297 SKIP(2);
8298 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008299 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008300 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008301 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8302 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00008303 SKIP_BLANKS;
8304 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008305 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8306 /* more ops could be optimized too */
8307 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8308 }
Owen Taylor3473f882001-02-23 17:55:21 +00008309}
8310
8311/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008312 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00008313 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008314 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00008315 *
8316 * [8] Predicate ::= '[' PredicateExpr ']'
8317 * [9] PredicateExpr ::= Expr
8318 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008319 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008320 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008321static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008322xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008323 int op1 = ctxt->comp->last;
8324
8325 SKIP_BLANKS;
8326 if (CUR != '[') {
8327 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8328 }
8329 NEXT;
8330 SKIP_BLANKS;
8331
8332 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008333 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008334 CHECK_ERROR;
8335
8336 if (CUR != ']') {
8337 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8338 }
8339
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008340 if (filter)
8341 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8342 else
8343 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008344
8345 NEXT;
8346 SKIP_BLANKS;
8347}
8348
8349/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008350 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00008351 * @ctxt: the XPath Parser context
8352 * @test: pointer to a xmlXPathTestVal
8353 * @type: pointer to a xmlXPathTypeVal
8354 * @prefix: placeholder for a possible name prefix
8355 *
8356 * [7] NodeTest ::= NameTest
8357 * | NodeType '(' ')'
8358 * | 'processing-instruction' '(' Literal ')'
8359 *
8360 * [37] NameTest ::= '*'
8361 * | NCName ':' '*'
8362 * | QName
8363 * [38] NodeType ::= 'comment'
8364 * | 'text'
8365 * | 'processing-instruction'
8366 * | 'node'
8367 *
8368 * Returns the name found and update @test, @type and @prefix appropriately
8369 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008370static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008371xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8372 xmlXPathTypeVal *type, const xmlChar **prefix,
8373 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008374 int blanks;
8375
8376 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8377 STRANGE;
8378 return(NULL);
8379 }
William M. Brack78637da2003-07-31 14:47:38 +00008380 *type = (xmlXPathTypeVal) 0;
8381 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008382 *prefix = NULL;
8383 SKIP_BLANKS;
8384
8385 if ((name == NULL) && (CUR == '*')) {
8386 /*
8387 * All elements
8388 */
8389 NEXT;
8390 *test = NODE_TEST_ALL;
8391 return(NULL);
8392 }
8393
8394 if (name == NULL)
8395 name = xmlXPathParseNCName(ctxt);
8396 if (name == NULL) {
8397 XP_ERROR0(XPATH_EXPR_ERROR);
8398 }
8399
8400 blanks = IS_BLANK(CUR);
8401 SKIP_BLANKS;
8402 if (CUR == '(') {
8403 NEXT;
8404 /*
8405 * NodeType or PI search
8406 */
8407 if (xmlStrEqual(name, BAD_CAST "comment"))
8408 *type = NODE_TYPE_COMMENT;
8409 else if (xmlStrEqual(name, BAD_CAST "node"))
8410 *type = NODE_TYPE_NODE;
8411 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8412 *type = NODE_TYPE_PI;
8413 else if (xmlStrEqual(name, BAD_CAST "text"))
8414 *type = NODE_TYPE_TEXT;
8415 else {
8416 if (name != NULL)
8417 xmlFree(name);
8418 XP_ERROR0(XPATH_EXPR_ERROR);
8419 }
8420
8421 *test = NODE_TEST_TYPE;
8422
8423 SKIP_BLANKS;
8424 if (*type == NODE_TYPE_PI) {
8425 /*
8426 * Specific case: search a PI by name.
8427 */
Owen Taylor3473f882001-02-23 17:55:21 +00008428 if (name != NULL)
8429 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008430 name = NULL;
8431 if (CUR != ')') {
8432 name = xmlXPathParseLiteral(ctxt);
8433 CHECK_ERROR 0;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00008434 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00008435 SKIP_BLANKS;
8436 }
Owen Taylor3473f882001-02-23 17:55:21 +00008437 }
8438 if (CUR != ')') {
8439 if (name != NULL)
8440 xmlFree(name);
8441 XP_ERROR0(XPATH_UNCLOSED_ERROR);
8442 }
8443 NEXT;
8444 return(name);
8445 }
8446 *test = NODE_TEST_NAME;
8447 if ((!blanks) && (CUR == ':')) {
8448 NEXT;
8449
8450 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008451 * Since currently the parser context don't have a
8452 * namespace list associated:
8453 * The namespace name for this prefix can be computed
8454 * only at evaluation time. The compilation is done
8455 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008456 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008457#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008458 *prefix = xmlXPathNsLookup(ctxt->context, name);
8459 if (name != NULL)
8460 xmlFree(name);
8461 if (*prefix == NULL) {
8462 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8463 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008464#else
8465 *prefix = name;
8466#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008467
8468 if (CUR == '*') {
8469 /*
8470 * All elements
8471 */
8472 NEXT;
8473 *test = NODE_TEST_ALL;
8474 return(NULL);
8475 }
8476
8477 name = xmlXPathParseNCName(ctxt);
8478 if (name == NULL) {
8479 XP_ERROR0(XPATH_EXPR_ERROR);
8480 }
8481 }
8482 return(name);
8483}
8484
8485/**
8486 * xmlXPathIsAxisName:
8487 * @name: a preparsed name token
8488 *
8489 * [6] AxisName ::= 'ancestor'
8490 * | 'ancestor-or-self'
8491 * | 'attribute'
8492 * | 'child'
8493 * | 'descendant'
8494 * | 'descendant-or-self'
8495 * | 'following'
8496 * | 'following-sibling'
8497 * | 'namespace'
8498 * | 'parent'
8499 * | 'preceding'
8500 * | 'preceding-sibling'
8501 * | 'self'
8502 *
8503 * Returns the axis or 0
8504 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008505static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008506xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +00008507 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008508 switch (name[0]) {
8509 case 'a':
8510 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8511 ret = AXIS_ANCESTOR;
8512 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8513 ret = AXIS_ANCESTOR_OR_SELF;
8514 if (xmlStrEqual(name, BAD_CAST "attribute"))
8515 ret = AXIS_ATTRIBUTE;
8516 break;
8517 case 'c':
8518 if (xmlStrEqual(name, BAD_CAST "child"))
8519 ret = AXIS_CHILD;
8520 break;
8521 case 'd':
8522 if (xmlStrEqual(name, BAD_CAST "descendant"))
8523 ret = AXIS_DESCENDANT;
8524 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8525 ret = AXIS_DESCENDANT_OR_SELF;
8526 break;
8527 case 'f':
8528 if (xmlStrEqual(name, BAD_CAST "following"))
8529 ret = AXIS_FOLLOWING;
8530 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8531 ret = AXIS_FOLLOWING_SIBLING;
8532 break;
8533 case 'n':
8534 if (xmlStrEqual(name, BAD_CAST "namespace"))
8535 ret = AXIS_NAMESPACE;
8536 break;
8537 case 'p':
8538 if (xmlStrEqual(name, BAD_CAST "parent"))
8539 ret = AXIS_PARENT;
8540 if (xmlStrEqual(name, BAD_CAST "preceding"))
8541 ret = AXIS_PRECEDING;
8542 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8543 ret = AXIS_PRECEDING_SIBLING;
8544 break;
8545 case 's':
8546 if (xmlStrEqual(name, BAD_CAST "self"))
8547 ret = AXIS_SELF;
8548 break;
8549 }
8550 return(ret);
8551}
8552
8553/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008554 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008555 * @ctxt: the XPath Parser context
8556 *
8557 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8558 * | AbbreviatedStep
8559 *
8560 * [12] AbbreviatedStep ::= '.' | '..'
8561 *
8562 * [5] AxisSpecifier ::= AxisName '::'
8563 * | AbbreviatedAxisSpecifier
8564 *
8565 * [13] AbbreviatedAxisSpecifier ::= '@'?
8566 *
8567 * Modified for XPtr range support as:
8568 *
8569 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8570 * | AbbreviatedStep
8571 * | 'range-to' '(' Expr ')' Predicate*
8572 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008573 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008574 * A location step of . is short for self::node(). This is
8575 * particularly useful in conjunction with //. For example, the
8576 * location path .//para is short for
8577 * self::node()/descendant-or-self::node()/child::para
8578 * and so will select all para descendant elements of the context
8579 * node.
8580 * Similarly, a location step of .. is short for parent::node().
8581 * For example, ../title is short for parent::node()/child::title
8582 * and so will select the title children of the parent of the context
8583 * node.
8584 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008585static void
8586xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008587#ifdef LIBXML_XPTR_ENABLED
8588 int rangeto = 0;
8589 int op2 = -1;
8590#endif
8591
Owen Taylor3473f882001-02-23 17:55:21 +00008592 SKIP_BLANKS;
8593 if ((CUR == '.') && (NXT(1) == '.')) {
8594 SKIP(2);
8595 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008596 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8597 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008598 } else if (CUR == '.') {
8599 NEXT;
8600 SKIP_BLANKS;
8601 } else {
8602 xmlChar *name = NULL;
8603 const xmlChar *prefix = NULL;
8604 xmlXPathTestVal test;
William M. Brack78637da2003-07-31 14:47:38 +00008605 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008606 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008607 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008608
8609 /*
8610 * The modification needed for XPointer change to the production
8611 */
8612#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008613 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008614 name = xmlXPathParseNCName(ctxt);
8615 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008616 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008617 xmlFree(name);
8618 SKIP_BLANKS;
8619 if (CUR != '(') {
8620 XP_ERROR(XPATH_EXPR_ERROR);
8621 }
8622 NEXT;
8623 SKIP_BLANKS;
8624
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008625 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008626 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008627 CHECK_ERROR;
8628
8629 SKIP_BLANKS;
8630 if (CUR != ')') {
8631 XP_ERROR(XPATH_EXPR_ERROR);
8632 }
8633 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008634 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008635 goto eval_predicates;
8636 }
8637 }
8638#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008639 if (CUR == '*') {
8640 axis = AXIS_CHILD;
8641 } else {
8642 if (name == NULL)
8643 name = xmlXPathParseNCName(ctxt);
8644 if (name != NULL) {
8645 axis = xmlXPathIsAxisName(name);
8646 if (axis != 0) {
8647 SKIP_BLANKS;
8648 if ((CUR == ':') && (NXT(1) == ':')) {
8649 SKIP(2);
8650 xmlFree(name);
8651 name = NULL;
8652 } else {
8653 /* an element name can conflict with an axis one :-\ */
8654 axis = AXIS_CHILD;
8655 }
Owen Taylor3473f882001-02-23 17:55:21 +00008656 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008657 axis = AXIS_CHILD;
8658 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008659 } else if (CUR == '@') {
8660 NEXT;
8661 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008662 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008663 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008664 }
Owen Taylor3473f882001-02-23 17:55:21 +00008665 }
8666
8667 CHECK_ERROR;
8668
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008669 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008670 if (test == 0)
8671 return;
8672
8673#ifdef DEBUG_STEP
8674 xmlGenericError(xmlGenericErrorContext,
8675 "Basis : computing new set\n");
8676#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008677
Owen Taylor3473f882001-02-23 17:55:21 +00008678#ifdef DEBUG_STEP
8679 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008680 if (ctxt->value == NULL)
8681 xmlGenericError(xmlGenericErrorContext, "no value\n");
8682 else if (ctxt->value->nodesetval == NULL)
8683 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8684 else
8685 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008686#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008687
8688eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008689 op1 = ctxt->comp->last;
8690 ctxt->comp->last = -1;
8691
Owen Taylor3473f882001-02-23 17:55:21 +00008692 SKIP_BLANKS;
8693 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008694 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008695 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008696
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008697#ifdef LIBXML_XPTR_ENABLED
8698 if (rangeto) {
8699 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8700 } else
8701#endif
8702 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8703 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008704
Owen Taylor3473f882001-02-23 17:55:21 +00008705 }
8706#ifdef DEBUG_STEP
8707 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008708 if (ctxt->value == NULL)
8709 xmlGenericError(xmlGenericErrorContext, "no value\n");
8710 else if (ctxt->value->nodesetval == NULL)
8711 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8712 else
8713 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8714 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008715#endif
8716}
8717
8718/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008719 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008720 * @ctxt: the XPath Parser context
8721 *
8722 * [3] RelativeLocationPath ::= Step
8723 * | RelativeLocationPath '/' Step
8724 * | AbbreviatedRelativeLocationPath
8725 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8726 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008727 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008728 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008729static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008730xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008731(xmlXPathParserContextPtr ctxt) {
8732 SKIP_BLANKS;
8733 if ((CUR == '/') && (NXT(1) == '/')) {
8734 SKIP(2);
8735 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008736 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8737 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008738 } else if (CUR == '/') {
8739 NEXT;
8740 SKIP_BLANKS;
8741 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008742 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008743 SKIP_BLANKS;
8744 while (CUR == '/') {
8745 if ((CUR == '/') && (NXT(1) == '/')) {
8746 SKIP(2);
8747 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008748 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008749 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008750 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008751 } else if (CUR == '/') {
8752 NEXT;
8753 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008754 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008755 }
8756 SKIP_BLANKS;
8757 }
8758}
8759
8760/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008761 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008762 * @ctxt: the XPath Parser context
8763 *
8764 * [1] LocationPath ::= RelativeLocationPath
8765 * | AbsoluteLocationPath
8766 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8767 * | AbbreviatedAbsoluteLocationPath
8768 * [10] AbbreviatedAbsoluteLocationPath ::=
8769 * '//' RelativeLocationPath
8770 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008771 * Compile a location path
8772 *
Owen Taylor3473f882001-02-23 17:55:21 +00008773 * // is short for /descendant-or-self::node()/. For example,
8774 * //para is short for /descendant-or-self::node()/child::para and
8775 * so will select any para element in the document (even a para element
8776 * that is a document element will be selected by //para since the
8777 * document element node is a child of the root node); div//para is
8778 * short for div/descendant-or-self::node()/child::para and so will
8779 * select all para descendants of div children.
8780 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008781static void
8782xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008783 SKIP_BLANKS;
8784 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008785 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008786 } else {
8787 while (CUR == '/') {
8788 if ((CUR == '/') && (NXT(1) == '/')) {
8789 SKIP(2);
8790 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008791 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8792 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008793 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008794 } else if (CUR == '/') {
8795 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008796 SKIP_BLANKS;
8797 if ((CUR != 0 ) &&
8798 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
8799 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008800 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008801 }
8802 }
8803 }
8804}
8805
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008806/************************************************************************
8807 * *
8808 * XPath precompiled expression evaluation *
8809 * *
8810 ************************************************************************/
8811
Daniel Veillardf06307e2001-07-03 10:35:50 +00008812static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008813xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8814
8815/**
8816 * xmlXPathNodeCollectAndTest:
8817 * @ctxt: the XPath Parser context
8818 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008819 * @first: pointer to the first element in document order
8820 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008821 *
8822 * This is the function implementing a step: based on the current list
8823 * of nodes, it builds up a new list, looking at all nodes under that
8824 * axis and selecting them it also do the predicate filtering
8825 *
8826 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00008827 *
8828 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008829 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008830static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008831xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008832 xmlXPathStepOpPtr op,
8833 xmlNodePtr * first, xmlNodePtr * last)
8834{
William M. Brack78637da2003-07-31 14:47:38 +00008835 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
8836 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
8837 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008838 const xmlChar *prefix = op->value4;
8839 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008840 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008841
8842#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008843 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008844#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008845 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008846 xmlNodeSetPtr ret, list;
8847 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008848 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00008849 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008850 xmlNodePtr cur = NULL;
8851 xmlXPathObjectPtr obj;
8852 xmlNodeSetPtr nodelist;
8853 xmlNodePtr tmp;
8854
Daniel Veillardf06307e2001-07-03 10:35:50 +00008855 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008856 obj = valuePop(ctxt);
8857 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00008858 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008859 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008860 URI = xmlXPathNsLookup(ctxt->context, prefix);
8861 if (URI == NULL)
8862 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008863 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008864#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008865 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008866#endif
8867 switch (axis) {
8868 case AXIS_ANCESTOR:
8869#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008870 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008871#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008872 first = NULL;
8873 next = xmlXPathNextAncestor;
8874 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008875 case AXIS_ANCESTOR_OR_SELF:
8876#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008877 xmlGenericError(xmlGenericErrorContext,
8878 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008879#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008880 first = NULL;
8881 next = xmlXPathNextAncestorOrSelf;
8882 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008883 case AXIS_ATTRIBUTE:
8884#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008885 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008886#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008887 first = NULL;
8888 last = NULL;
8889 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00008890 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008891 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008892 case AXIS_CHILD:
8893#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008894 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008895#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008896 last = NULL;
8897 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00008898 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008899 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008900 case AXIS_DESCENDANT:
8901#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008902 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008903#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008904 last = NULL;
8905 next = xmlXPathNextDescendant;
8906 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008907 case AXIS_DESCENDANT_OR_SELF:
8908#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008909 xmlGenericError(xmlGenericErrorContext,
8910 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008911#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008912 last = NULL;
8913 next = xmlXPathNextDescendantOrSelf;
8914 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008915 case AXIS_FOLLOWING:
8916#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008917 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008918#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008919 last = NULL;
8920 next = xmlXPathNextFollowing;
8921 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008922 case AXIS_FOLLOWING_SIBLING:
8923#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008924 xmlGenericError(xmlGenericErrorContext,
8925 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008926#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008927 last = NULL;
8928 next = xmlXPathNextFollowingSibling;
8929 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008930 case AXIS_NAMESPACE:
8931#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008932 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008933#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008934 first = NULL;
8935 last = NULL;
8936 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00008937 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008938 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008939 case AXIS_PARENT:
8940#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008941 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008942#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008943 first = NULL;
8944 next = xmlXPathNextParent;
8945 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008946 case AXIS_PRECEDING:
8947#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008948 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008949#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008950 first = NULL;
8951 next = xmlXPathNextPrecedingInternal;
8952 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008953 case AXIS_PRECEDING_SIBLING:
8954#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008955 xmlGenericError(xmlGenericErrorContext,
8956 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008957#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008958 first = NULL;
8959 next = xmlXPathNextPrecedingSibling;
8960 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008961 case AXIS_SELF:
8962#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008963 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008964#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008965 first = NULL;
8966 last = NULL;
8967 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00008968 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008969 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008970 }
8971 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008972 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008973
8974 nodelist = obj->nodesetval;
8975 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008976 xmlXPathFreeObject(obj);
8977 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8978 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008979 }
8980 addNode = xmlXPathNodeSetAddUnique;
8981 ret = NULL;
8982#ifdef DEBUG_STEP
8983 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008984 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008985 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008986 case NODE_TEST_NONE:
8987 xmlGenericError(xmlGenericErrorContext,
8988 " searching for none !!!\n");
8989 break;
8990 case NODE_TEST_TYPE:
8991 xmlGenericError(xmlGenericErrorContext,
8992 " searching for type %d\n", type);
8993 break;
8994 case NODE_TEST_PI:
8995 xmlGenericError(xmlGenericErrorContext,
8996 " searching for PI !!!\n");
8997 break;
8998 case NODE_TEST_ALL:
8999 xmlGenericError(xmlGenericErrorContext,
9000 " searching for *\n");
9001 break;
9002 case NODE_TEST_NS:
9003 xmlGenericError(xmlGenericErrorContext,
9004 " searching for namespace %s\n",
9005 prefix);
9006 break;
9007 case NODE_TEST_NAME:
9008 xmlGenericError(xmlGenericErrorContext,
9009 " searching for name %s\n", name);
9010 if (prefix != NULL)
9011 xmlGenericError(xmlGenericErrorContext,
9012 " with namespace %s\n", prefix);
9013 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009014 }
9015 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9016#endif
9017 /*
9018 * 2.3 Node Tests
9019 * - For the attribute axis, the principal node type is attribute.
9020 * - For the namespace axis, the principal node type is namespace.
9021 * - For other axes, the principal node type is element.
9022 *
9023 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009024 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009025 * select all element children of the context node
9026 */
9027 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009028 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009029 ctxt->context->node = nodelist->nodeTab[i];
9030
Daniel Veillardf06307e2001-07-03 10:35:50 +00009031 cur = NULL;
9032 list = xmlXPathNodeSetCreate(NULL);
9033 do {
9034 cur = next(ctxt, cur);
9035 if (cur == NULL)
9036 break;
9037 if ((first != NULL) && (*first == cur))
9038 break;
9039 if (((t % 256) == 0) &&
9040 (first != NULL) && (*first != NULL) &&
9041 (xmlXPathCmpNodes(*first, cur) >= 0))
9042 break;
9043 if ((last != NULL) && (*last == cur))
9044 break;
9045 if (((t % 256) == 0) &&
9046 (last != NULL) && (*last != NULL) &&
9047 (xmlXPathCmpNodes(cur, *last) >= 0))
9048 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009049 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009050#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009051 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
9052#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009053 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009054 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009055 ctxt->context->node = tmp;
9056 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009057 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009058 if ((cur->type == type) ||
9059 ((type == NODE_TYPE_NODE) &&
9060 ((cur->type == XML_DOCUMENT_NODE) ||
9061 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9062 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00009063 (cur->type == XML_NAMESPACE_DECL) ||
9064 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00009065 (cur->type == XML_PI_NODE) ||
9066 (cur->type == XML_COMMENT_NODE) ||
9067 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00009068 (cur->type == XML_TEXT_NODE))) ||
9069 ((type == NODE_TYPE_TEXT) &&
9070 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009071#ifdef DEBUG_STEP
9072 n++;
9073#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009074 addNode(list, cur);
9075 }
9076 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009077 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009078 if (cur->type == XML_PI_NODE) {
9079 if ((name != NULL) &&
9080 (!xmlStrEqual(name, cur->name)))
9081 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009082#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009083 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009084#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009085 addNode(list, cur);
9086 }
9087 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009088 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009089 if (axis == AXIS_ATTRIBUTE) {
9090 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009091#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009092 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009093#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009094 addNode(list, cur);
9095 }
9096 } else if (axis == AXIS_NAMESPACE) {
9097 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009098#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009099 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009100#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009101 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9102 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009103 }
9104 } else {
9105 if (cur->type == XML_ELEMENT_NODE) {
9106 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009107#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009108 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009109#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009110 addNode(list, cur);
9111 } else if ((cur->ns != NULL) &&
9112 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009113#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009114 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009115#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009116 addNode(list, cur);
9117 }
9118 }
9119 }
9120 break;
9121 case NODE_TEST_NS:{
9122 TODO;
9123 break;
9124 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009125 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009126 switch (cur->type) {
9127 case XML_ELEMENT_NODE:
9128 if (xmlStrEqual(name, cur->name)) {
9129 if (prefix == NULL) {
9130 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009131#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009132 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009133#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009134 addNode(list, cur);
9135 }
9136 } else {
9137 if ((cur->ns != NULL) &&
9138 (xmlStrEqual(URI,
9139 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009140#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009141 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009142#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009143 addNode(list, cur);
9144 }
9145 }
9146 }
9147 break;
9148 case XML_ATTRIBUTE_NODE:{
9149 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009150
Daniel Veillardf06307e2001-07-03 10:35:50 +00009151 if (xmlStrEqual(name, attr->name)) {
9152 if (prefix == NULL) {
9153 if ((attr->ns == NULL) ||
9154 (attr->ns->prefix == NULL)) {
9155#ifdef DEBUG_STEP
9156 n++;
9157#endif
9158 addNode(list,
9159 (xmlNodePtr) attr);
9160 }
9161 } else {
9162 if ((attr->ns != NULL) &&
9163 (xmlStrEqual(URI,
9164 attr->ns->
9165 href))) {
9166#ifdef DEBUG_STEP
9167 n++;
9168#endif
9169 addNode(list,
9170 (xmlNodePtr) attr);
9171 }
9172 }
9173 }
9174 break;
9175 }
9176 case XML_NAMESPACE_DECL:
9177 if (cur->type == XML_NAMESPACE_DECL) {
9178 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009179
Daniel Veillardf06307e2001-07-03 10:35:50 +00009180 if ((ns->prefix != NULL) && (name != NULL)
9181 && (xmlStrEqual(ns->prefix, name))) {
9182#ifdef DEBUG_STEP
9183 n++;
9184#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009185 xmlXPathNodeSetAddNs(list,
9186 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009187 }
9188 }
9189 break;
9190 default:
9191 break;
9192 }
9193 break;
9194 break;
9195 }
9196 } while (cur != NULL);
9197
9198 /*
9199 * If there is some predicate filtering do it now
9200 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009201 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009202 xmlXPathObjectPtr obj2;
9203
9204 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9205 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9206 CHECK_TYPE0(XPATH_NODESET);
9207 obj2 = valuePop(ctxt);
9208 list = obj2->nodesetval;
9209 obj2->nodesetval = NULL;
9210 xmlXPathFreeObject(obj2);
9211 }
9212 if (ret == NULL) {
9213 ret = list;
9214 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009215 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009216 xmlXPathFreeNodeSet(list);
9217 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009218 }
9219 ctxt->context->node = tmp;
9220#ifdef DEBUG_STEP
9221 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009222 "\nExamined %d nodes, found %d nodes at that step\n",
9223 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009224#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009225 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009226 if ((obj->boolval) && (obj->user != NULL)) {
9227 ctxt->value->boolval = 1;
9228 ctxt->value->user = obj->user;
9229 obj->user = NULL;
9230 obj->boolval = 0;
9231 }
9232 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009233 return(t);
9234}
9235
9236/**
9237 * xmlXPathNodeCollectAndTestNth:
9238 * @ctxt: the XPath Parser context
9239 * @op: the XPath precompiled step operation
9240 * @indx: the index to collect
9241 * @first: pointer to the first element in document order
9242 * @last: pointer to the last element in document order
9243 *
9244 * This is the function implementing a step: based on the current list
9245 * of nodes, it builds up a new list, looking at all nodes under that
9246 * axis and selecting them it also do the predicate filtering
9247 *
9248 * Pushes the new NodeSet resulting from the search.
9249 * Returns the number of node traversed
9250 */
9251static int
9252xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9253 xmlXPathStepOpPtr op, int indx,
9254 xmlNodePtr * first, xmlNodePtr * last)
9255{
William M. Brack78637da2003-07-31 14:47:38 +00009256 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9257 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9258 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009259 const xmlChar *prefix = op->value4;
9260 const xmlChar *name = op->value5;
9261 const xmlChar *URI = NULL;
9262 int n = 0, t = 0;
9263
9264 int i;
9265 xmlNodeSetPtr list;
9266 xmlXPathTraversalFunction next = NULL;
9267 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9268 xmlNodePtr cur = NULL;
9269 xmlXPathObjectPtr obj;
9270 xmlNodeSetPtr nodelist;
9271 xmlNodePtr tmp;
9272
9273 CHECK_TYPE0(XPATH_NODESET);
9274 obj = valuePop(ctxt);
9275 addNode = xmlXPathNodeSetAdd;
9276 if (prefix != NULL) {
9277 URI = xmlXPathNsLookup(ctxt->context, prefix);
9278 if (URI == NULL)
9279 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9280 }
9281#ifdef DEBUG_STEP_NTH
9282 xmlGenericError(xmlGenericErrorContext, "new step : ");
9283 if (first != NULL) {
9284 if (*first != NULL)
9285 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9286 (*first)->name);
9287 else
9288 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9289 }
9290 if (last != NULL) {
9291 if (*last != NULL)
9292 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9293 (*last)->name);
9294 else
9295 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9296 }
9297#endif
9298 switch (axis) {
9299 case AXIS_ANCESTOR:
9300#ifdef DEBUG_STEP_NTH
9301 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9302#endif
9303 first = NULL;
9304 next = xmlXPathNextAncestor;
9305 break;
9306 case AXIS_ANCESTOR_OR_SELF:
9307#ifdef DEBUG_STEP_NTH
9308 xmlGenericError(xmlGenericErrorContext,
9309 "axis 'ancestors-or-self' ");
9310#endif
9311 first = NULL;
9312 next = xmlXPathNextAncestorOrSelf;
9313 break;
9314 case AXIS_ATTRIBUTE:
9315#ifdef DEBUG_STEP_NTH
9316 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9317#endif
9318 first = NULL;
9319 last = NULL;
9320 next = xmlXPathNextAttribute;
9321 break;
9322 case AXIS_CHILD:
9323#ifdef DEBUG_STEP_NTH
9324 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9325#endif
9326 last = NULL;
9327 next = xmlXPathNextChild;
9328 break;
9329 case AXIS_DESCENDANT:
9330#ifdef DEBUG_STEP_NTH
9331 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9332#endif
9333 last = NULL;
9334 next = xmlXPathNextDescendant;
9335 break;
9336 case AXIS_DESCENDANT_OR_SELF:
9337#ifdef DEBUG_STEP_NTH
9338 xmlGenericError(xmlGenericErrorContext,
9339 "axis 'descendant-or-self' ");
9340#endif
9341 last = NULL;
9342 next = xmlXPathNextDescendantOrSelf;
9343 break;
9344 case AXIS_FOLLOWING:
9345#ifdef DEBUG_STEP_NTH
9346 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9347#endif
9348 last = NULL;
9349 next = xmlXPathNextFollowing;
9350 break;
9351 case AXIS_FOLLOWING_SIBLING:
9352#ifdef DEBUG_STEP_NTH
9353 xmlGenericError(xmlGenericErrorContext,
9354 "axis 'following-siblings' ");
9355#endif
9356 last = NULL;
9357 next = xmlXPathNextFollowingSibling;
9358 break;
9359 case AXIS_NAMESPACE:
9360#ifdef DEBUG_STEP_NTH
9361 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9362#endif
9363 last = NULL;
9364 first = NULL;
9365 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9366 break;
9367 case AXIS_PARENT:
9368#ifdef DEBUG_STEP_NTH
9369 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9370#endif
9371 first = NULL;
9372 next = xmlXPathNextParent;
9373 break;
9374 case AXIS_PRECEDING:
9375#ifdef DEBUG_STEP_NTH
9376 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9377#endif
9378 first = NULL;
9379 next = xmlXPathNextPrecedingInternal;
9380 break;
9381 case AXIS_PRECEDING_SIBLING:
9382#ifdef DEBUG_STEP_NTH
9383 xmlGenericError(xmlGenericErrorContext,
9384 "axis 'preceding-sibling' ");
9385#endif
9386 first = NULL;
9387 next = xmlXPathNextPrecedingSibling;
9388 break;
9389 case AXIS_SELF:
9390#ifdef DEBUG_STEP_NTH
9391 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9392#endif
9393 first = NULL;
9394 last = NULL;
9395 next = xmlXPathNextSelf;
9396 break;
9397 }
9398 if (next == NULL)
9399 return(0);
9400
9401 nodelist = obj->nodesetval;
9402 if (nodelist == NULL) {
9403 xmlXPathFreeObject(obj);
9404 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9405 return(0);
9406 }
9407 addNode = xmlXPathNodeSetAddUnique;
9408#ifdef DEBUG_STEP_NTH
9409 xmlGenericError(xmlGenericErrorContext,
9410 " context contains %d nodes\n", nodelist->nodeNr);
9411 switch (test) {
9412 case NODE_TEST_NONE:
9413 xmlGenericError(xmlGenericErrorContext,
9414 " searching for none !!!\n");
9415 break;
9416 case NODE_TEST_TYPE:
9417 xmlGenericError(xmlGenericErrorContext,
9418 " searching for type %d\n", type);
9419 break;
9420 case NODE_TEST_PI:
9421 xmlGenericError(xmlGenericErrorContext,
9422 " searching for PI !!!\n");
9423 break;
9424 case NODE_TEST_ALL:
9425 xmlGenericError(xmlGenericErrorContext,
9426 " searching for *\n");
9427 break;
9428 case NODE_TEST_NS:
9429 xmlGenericError(xmlGenericErrorContext,
9430 " searching for namespace %s\n",
9431 prefix);
9432 break;
9433 case NODE_TEST_NAME:
9434 xmlGenericError(xmlGenericErrorContext,
9435 " searching for name %s\n", name);
9436 if (prefix != NULL)
9437 xmlGenericError(xmlGenericErrorContext,
9438 " with namespace %s\n", prefix);
9439 break;
9440 }
9441 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9442#endif
9443 /*
9444 * 2.3 Node Tests
9445 * - For the attribute axis, the principal node type is attribute.
9446 * - For the namespace axis, the principal node type is namespace.
9447 * - For other axes, the principal node type is element.
9448 *
9449 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009450 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009451 * select all element children of the context node
9452 */
9453 tmp = ctxt->context->node;
9454 list = xmlXPathNodeSetCreate(NULL);
9455 for (i = 0; i < nodelist->nodeNr; i++) {
9456 ctxt->context->node = nodelist->nodeTab[i];
9457
9458 cur = NULL;
9459 n = 0;
9460 do {
9461 cur = next(ctxt, cur);
9462 if (cur == NULL)
9463 break;
9464 if ((first != NULL) && (*first == cur))
9465 break;
9466 if (((t % 256) == 0) &&
9467 (first != NULL) && (*first != NULL) &&
9468 (xmlXPathCmpNodes(*first, cur) >= 0))
9469 break;
9470 if ((last != NULL) && (*last == cur))
9471 break;
9472 if (((t % 256) == 0) &&
9473 (last != NULL) && (*last != NULL) &&
9474 (xmlXPathCmpNodes(cur, *last) >= 0))
9475 break;
9476 t++;
9477 switch (test) {
9478 case NODE_TEST_NONE:
9479 ctxt->context->node = tmp;
9480 STRANGE return(0);
9481 case NODE_TEST_TYPE:
9482 if ((cur->type == type) ||
9483 ((type == NODE_TYPE_NODE) &&
9484 ((cur->type == XML_DOCUMENT_NODE) ||
9485 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9486 (cur->type == XML_ELEMENT_NODE) ||
9487 (cur->type == XML_PI_NODE) ||
9488 (cur->type == XML_COMMENT_NODE) ||
9489 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +00009490 (cur->type == XML_TEXT_NODE))) ||
9491 ((type == NODE_TYPE_TEXT) &&
9492 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009493 n++;
9494 if (n == indx)
9495 addNode(list, cur);
9496 }
9497 break;
9498 case NODE_TEST_PI:
9499 if (cur->type == XML_PI_NODE) {
9500 if ((name != NULL) &&
9501 (!xmlStrEqual(name, cur->name)))
9502 break;
9503 n++;
9504 if (n == indx)
9505 addNode(list, cur);
9506 }
9507 break;
9508 case NODE_TEST_ALL:
9509 if (axis == AXIS_ATTRIBUTE) {
9510 if (cur->type == XML_ATTRIBUTE_NODE) {
9511 n++;
9512 if (n == indx)
9513 addNode(list, cur);
9514 }
9515 } else if (axis == AXIS_NAMESPACE) {
9516 if (cur->type == XML_NAMESPACE_DECL) {
9517 n++;
9518 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009519 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9520 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009521 }
9522 } else {
9523 if (cur->type == XML_ELEMENT_NODE) {
9524 if (prefix == NULL) {
9525 n++;
9526 if (n == indx)
9527 addNode(list, cur);
9528 } else if ((cur->ns != NULL) &&
9529 (xmlStrEqual(URI, cur->ns->href))) {
9530 n++;
9531 if (n == indx)
9532 addNode(list, cur);
9533 }
9534 }
9535 }
9536 break;
9537 case NODE_TEST_NS:{
9538 TODO;
9539 break;
9540 }
9541 case NODE_TEST_NAME:
9542 switch (cur->type) {
9543 case XML_ELEMENT_NODE:
9544 if (xmlStrEqual(name, cur->name)) {
9545 if (prefix == NULL) {
9546 if (cur->ns == NULL) {
9547 n++;
9548 if (n == indx)
9549 addNode(list, cur);
9550 }
9551 } else {
9552 if ((cur->ns != NULL) &&
9553 (xmlStrEqual(URI,
9554 cur->ns->href))) {
9555 n++;
9556 if (n == indx)
9557 addNode(list, cur);
9558 }
9559 }
9560 }
9561 break;
9562 case XML_ATTRIBUTE_NODE:{
9563 xmlAttrPtr attr = (xmlAttrPtr) cur;
9564
9565 if (xmlStrEqual(name, attr->name)) {
9566 if (prefix == NULL) {
9567 if ((attr->ns == NULL) ||
9568 (attr->ns->prefix == NULL)) {
9569 n++;
9570 if (n == indx)
9571 addNode(list, cur);
9572 }
9573 } else {
9574 if ((attr->ns != NULL) &&
9575 (xmlStrEqual(URI,
9576 attr->ns->
9577 href))) {
9578 n++;
9579 if (n == indx)
9580 addNode(list, cur);
9581 }
9582 }
9583 }
9584 break;
9585 }
9586 case XML_NAMESPACE_DECL:
9587 if (cur->type == XML_NAMESPACE_DECL) {
9588 xmlNsPtr ns = (xmlNsPtr) cur;
9589
9590 if ((ns->prefix != NULL) && (name != NULL)
9591 && (xmlStrEqual(ns->prefix, name))) {
9592 n++;
9593 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009594 xmlXPathNodeSetAddNs(list,
9595 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009596 }
9597 }
9598 break;
9599 default:
9600 break;
9601 }
9602 break;
9603 break;
9604 }
9605 } while (n < indx);
9606 }
9607 ctxt->context->node = tmp;
9608#ifdef DEBUG_STEP_NTH
9609 xmlGenericError(xmlGenericErrorContext,
9610 "\nExamined %d nodes, found %d nodes at that step\n",
9611 t, list->nodeNr);
9612#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009613 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009614 if ((obj->boolval) && (obj->user != NULL)) {
9615 ctxt->value->boolval = 1;
9616 ctxt->value->user = obj->user;
9617 obj->user = NULL;
9618 obj->boolval = 0;
9619 }
9620 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009621 return(t);
9622}
9623
9624/**
9625 * xmlXPathCompOpEvalFirst:
9626 * @ctxt: the XPath parser context with the compiled expression
9627 * @op: an XPath compiled operation
9628 * @first: the first elem found so far
9629 *
9630 * Evaluate the Precompiled XPath operation searching only the first
9631 * element in document order
9632 *
9633 * Returns the number of examined objects.
9634 */
9635static int
9636xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9637 xmlXPathStepOpPtr op, xmlNodePtr * first)
9638{
9639 int total = 0, cur;
9640 xmlXPathCompExprPtr comp;
9641 xmlXPathObjectPtr arg1, arg2;
9642
Daniel Veillard556c6682001-10-06 09:59:51 +00009643 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009644 comp = ctxt->comp;
9645 switch (op->op) {
9646 case XPATH_OP_END:
9647 return (0);
9648 case XPATH_OP_UNION:
9649 total =
9650 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9651 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009652 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009653 if ((ctxt->value != NULL)
9654 && (ctxt->value->type == XPATH_NODESET)
9655 && (ctxt->value->nodesetval != NULL)
9656 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9657 /*
9658 * limit tree traversing to first node in the result
9659 */
9660 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9661 *first = ctxt->value->nodesetval->nodeTab[0];
9662 }
9663 cur =
9664 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9665 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009666 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009667 CHECK_TYPE0(XPATH_NODESET);
9668 arg2 = valuePop(ctxt);
9669
9670 CHECK_TYPE0(XPATH_NODESET);
9671 arg1 = valuePop(ctxt);
9672
9673 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9674 arg2->nodesetval);
9675 valuePush(ctxt, arg1);
9676 xmlXPathFreeObject(arg2);
9677 /* optimizer */
9678 if (total > cur)
9679 xmlXPathCompSwap(op);
9680 return (total + cur);
9681 case XPATH_OP_ROOT:
9682 xmlXPathRoot(ctxt);
9683 return (0);
9684 case XPATH_OP_NODE:
9685 if (op->ch1 != -1)
9686 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009687 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009688 if (op->ch2 != -1)
9689 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009690 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009691 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9692 return (total);
9693 case XPATH_OP_RESET:
9694 if (op->ch1 != -1)
9695 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009696 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009697 if (op->ch2 != -1)
9698 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009699 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009700 ctxt->context->node = NULL;
9701 return (total);
9702 case XPATH_OP_COLLECT:{
9703 if (op->ch1 == -1)
9704 return (total);
9705
9706 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009707 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009708
9709 /*
9710 * Optimization for [n] selection where n is a number
9711 */
9712 if ((op->ch2 != -1) &&
9713 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9714 (comp->steps[op->ch2].ch1 == -1) &&
9715 (comp->steps[op->ch2].ch2 != -1) &&
9716 (comp->steps[comp->steps[op->ch2].ch2].op ==
9717 XPATH_OP_VALUE)) {
9718 xmlXPathObjectPtr val;
9719
9720 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9721 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9722 int indx = (int) val->floatval;
9723
9724 if (val->floatval == (float) indx) {
9725 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9726 first, NULL);
9727 return (total);
9728 }
9729 }
9730 }
9731 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9732 return (total);
9733 }
9734 case XPATH_OP_VALUE:
9735 valuePush(ctxt,
9736 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9737 return (0);
9738 case XPATH_OP_SORT:
9739 if (op->ch1 != -1)
9740 total +=
9741 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9742 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009743 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009744 if ((ctxt->value != NULL)
9745 && (ctxt->value->type == XPATH_NODESET)
9746 && (ctxt->value->nodesetval != NULL))
9747 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9748 return (total);
9749 default:
9750 return (xmlXPathCompOpEval(ctxt, op));
9751 }
9752}
9753
9754/**
9755 * xmlXPathCompOpEvalLast:
9756 * @ctxt: the XPath parser context with the compiled expression
9757 * @op: an XPath compiled operation
9758 * @last: the last elem found so far
9759 *
9760 * Evaluate the Precompiled XPath operation searching only the last
9761 * element in document order
9762 *
9763 * Returns the number of node traversed
9764 */
9765static int
9766xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9767 xmlNodePtr * last)
9768{
9769 int total = 0, cur;
9770 xmlXPathCompExprPtr comp;
9771 xmlXPathObjectPtr arg1, arg2;
9772
Daniel Veillard556c6682001-10-06 09:59:51 +00009773 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009774 comp = ctxt->comp;
9775 switch (op->op) {
9776 case XPATH_OP_END:
9777 return (0);
9778 case XPATH_OP_UNION:
9779 total =
9780 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009781 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009782 if ((ctxt->value != NULL)
9783 && (ctxt->value->type == XPATH_NODESET)
9784 && (ctxt->value->nodesetval != NULL)
9785 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9786 /*
9787 * limit tree traversing to first node in the result
9788 */
9789 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9790 *last =
9791 ctxt->value->nodesetval->nodeTab[ctxt->value->
9792 nodesetval->nodeNr -
9793 1];
9794 }
9795 cur =
9796 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009797 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009798 if ((ctxt->value != NULL)
9799 && (ctxt->value->type == XPATH_NODESET)
9800 && (ctxt->value->nodesetval != NULL)
9801 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9802 }
9803 CHECK_TYPE0(XPATH_NODESET);
9804 arg2 = valuePop(ctxt);
9805
9806 CHECK_TYPE0(XPATH_NODESET);
9807 arg1 = valuePop(ctxt);
9808
9809 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9810 arg2->nodesetval);
9811 valuePush(ctxt, arg1);
9812 xmlXPathFreeObject(arg2);
9813 /* optimizer */
9814 if (total > cur)
9815 xmlXPathCompSwap(op);
9816 return (total + cur);
9817 case XPATH_OP_ROOT:
9818 xmlXPathRoot(ctxt);
9819 return (0);
9820 case XPATH_OP_NODE:
9821 if (op->ch1 != -1)
9822 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009823 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009824 if (op->ch2 != -1)
9825 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009826 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009827 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9828 return (total);
9829 case XPATH_OP_RESET:
9830 if (op->ch1 != -1)
9831 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009832 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009833 if (op->ch2 != -1)
9834 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009835 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009836 ctxt->context->node = NULL;
9837 return (total);
9838 case XPATH_OP_COLLECT:{
9839 if (op->ch1 == -1)
9840 return (0);
9841
9842 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009843 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009844
9845 /*
9846 * Optimization for [n] selection where n is a number
9847 */
9848 if ((op->ch2 != -1) &&
9849 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9850 (comp->steps[op->ch2].ch1 == -1) &&
9851 (comp->steps[op->ch2].ch2 != -1) &&
9852 (comp->steps[comp->steps[op->ch2].ch2].op ==
9853 XPATH_OP_VALUE)) {
9854 xmlXPathObjectPtr val;
9855
9856 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9857 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9858 int indx = (int) val->floatval;
9859
9860 if (val->floatval == (float) indx) {
9861 total +=
9862 xmlXPathNodeCollectAndTestNth(ctxt, op,
9863 indx, NULL,
9864 last);
9865 return (total);
9866 }
9867 }
9868 }
9869 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9870 return (total);
9871 }
9872 case XPATH_OP_VALUE:
9873 valuePush(ctxt,
9874 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9875 return (0);
9876 case XPATH_OP_SORT:
9877 if (op->ch1 != -1)
9878 total +=
9879 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9880 last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009881 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009882 if ((ctxt->value != NULL)
9883 && (ctxt->value->type == XPATH_NODESET)
9884 && (ctxt->value->nodesetval != NULL))
9885 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9886 return (total);
9887 default:
9888 return (xmlXPathCompOpEval(ctxt, op));
9889 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009890}
9891
Owen Taylor3473f882001-02-23 17:55:21 +00009892/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009893 * xmlXPathCompOpEval:
9894 * @ctxt: the XPath parser context with the compiled expression
9895 * @op: an XPath compiled operation
9896 *
9897 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009898 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009899 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009900static int
9901xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9902{
9903 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009904 int equal, ret;
9905 xmlXPathCompExprPtr comp;
9906 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009907 xmlNodePtr bak;
9908 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +00009909 int pp;
William M. Brack692092b2002-06-28 15:01:24 +00009910 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009911
Daniel Veillard556c6682001-10-06 09:59:51 +00009912 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009913 comp = ctxt->comp;
9914 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009915 case XPATH_OP_END:
9916 return (0);
9917 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009918 bakd = ctxt->context->doc;
9919 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009920 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009921 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009922 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009923 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009924 xmlXPathBooleanFunction(ctxt, 1);
9925 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9926 return (total);
9927 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009928 ctxt->context->doc = bakd;
9929 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009930 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009931 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009932 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009933 if (ctxt->error) {
9934 xmlXPathFreeObject(arg2);
9935 return(0);
9936 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009937 xmlXPathBooleanFunction(ctxt, 1);
9938 arg1 = valuePop(ctxt);
9939 arg1->boolval &= arg2->boolval;
9940 valuePush(ctxt, arg1);
9941 xmlXPathFreeObject(arg2);
9942 return (total);
9943 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009944 bakd = ctxt->context->doc;
9945 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009946 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009947 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009948 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009949 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009950 xmlXPathBooleanFunction(ctxt, 1);
9951 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9952 return (total);
9953 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009954 ctxt->context->doc = bakd;
9955 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009956 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009957 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009958 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009959 if (ctxt->error) {
9960 xmlXPathFreeObject(arg2);
9961 return(0);
9962 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009963 xmlXPathBooleanFunction(ctxt, 1);
9964 arg1 = valuePop(ctxt);
9965 arg1->boolval |= arg2->boolval;
9966 valuePush(ctxt, arg1);
9967 xmlXPathFreeObject(arg2);
9968 return (total);
9969 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009970 bakd = ctxt->context->doc;
9971 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009972 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009973 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009974 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009975 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009976 ctxt->context->doc = bakd;
9977 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009978 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009979 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009980 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009981 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +00009982 if (op->value)
9983 equal = xmlXPathEqualValues(ctxt);
9984 else
9985 equal = xmlXPathNotEqualValues(ctxt);
9986 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +00009987 return (total);
9988 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009989 bakd = ctxt->context->doc;
9990 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009991 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009992 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009993 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009994 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009995 ctxt->context->doc = bakd;
9996 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009997 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009998 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009999 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010000 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010001 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
10002 valuePush(ctxt, xmlXPathNewBoolean(ret));
10003 return (total);
10004 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010005 bakd = ctxt->context->doc;
10006 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010007 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010008 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010009 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010010 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010011 if (op->ch2 != -1) {
10012 ctxt->context->doc = bakd;
10013 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010014 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010015 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010016 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010017 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010018 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010019 if (op->value == 0)
10020 xmlXPathSubValues(ctxt);
10021 else if (op->value == 1)
10022 xmlXPathAddValues(ctxt);
10023 else if (op->value == 2)
10024 xmlXPathValueFlipSign(ctxt);
10025 else if (op->value == 3) {
10026 CAST_TO_NUMBER;
10027 CHECK_TYPE0(XPATH_NUMBER);
10028 }
10029 return (total);
10030 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010031 bakd = ctxt->context->doc;
10032 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010033 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010034 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010035 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010036 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010037 ctxt->context->doc = bakd;
10038 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010039 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010040 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010041 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010042 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010043 if (op->value == 0)
10044 xmlXPathMultValues(ctxt);
10045 else if (op->value == 1)
10046 xmlXPathDivValues(ctxt);
10047 else if (op->value == 2)
10048 xmlXPathModValues(ctxt);
10049 return (total);
10050 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010051 bakd = ctxt->context->doc;
10052 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010053 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010054 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010055 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010056 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010057 ctxt->context->doc = bakd;
10058 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010059 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010060 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010061 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010062 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010063 CHECK_TYPE0(XPATH_NODESET);
10064 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010065
Daniel Veillardf06307e2001-07-03 10:35:50 +000010066 CHECK_TYPE0(XPATH_NODESET);
10067 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010068
Daniel Veillardf06307e2001-07-03 10:35:50 +000010069 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10070 arg2->nodesetval);
10071 valuePush(ctxt, arg1);
10072 xmlXPathFreeObject(arg2);
10073 return (total);
10074 case XPATH_OP_ROOT:
10075 xmlXPathRoot(ctxt);
10076 return (total);
10077 case XPATH_OP_NODE:
10078 if (op->ch1 != -1)
10079 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010080 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010081 if (op->ch2 != -1)
10082 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010083 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010084 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10085 return (total);
10086 case XPATH_OP_RESET:
10087 if (op->ch1 != -1)
10088 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010089 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010090 if (op->ch2 != -1)
10091 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010092 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010093 ctxt->context->node = NULL;
10094 return (total);
10095 case XPATH_OP_COLLECT:{
10096 if (op->ch1 == -1)
10097 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010098
Daniel Veillardf06307e2001-07-03 10:35:50 +000010099 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010100 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010101
Daniel Veillardf06307e2001-07-03 10:35:50 +000010102 /*
10103 * Optimization for [n] selection where n is a number
10104 */
10105 if ((op->ch2 != -1) &&
10106 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10107 (comp->steps[op->ch2].ch1 == -1) &&
10108 (comp->steps[op->ch2].ch2 != -1) &&
10109 (comp->steps[comp->steps[op->ch2].ch2].op ==
10110 XPATH_OP_VALUE)) {
10111 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +000010112
Daniel Veillardf06307e2001-07-03 10:35:50 +000010113 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10114 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10115 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010116
Daniel Veillardf06307e2001-07-03 10:35:50 +000010117 if (val->floatval == (float) indx) {
10118 total +=
10119 xmlXPathNodeCollectAndTestNth(ctxt, op,
10120 indx, NULL,
10121 NULL);
10122 return (total);
10123 }
10124 }
10125 }
10126 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
10127 return (total);
10128 }
10129 case XPATH_OP_VALUE:
10130 valuePush(ctxt,
10131 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10132 return (total);
10133 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000010134 xmlXPathObjectPtr val;
10135
Daniel Veillardf06307e2001-07-03 10:35:50 +000010136 if (op->ch1 != -1)
10137 total +=
10138 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010139 if (op->value5 == NULL) {
10140 val = xmlXPathVariableLookup(ctxt->context, op->value4);
10141 if (val == NULL) {
10142 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10143 return(0);
10144 }
10145 valuePush(ctxt, val);
10146 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010147 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010148
Daniel Veillardf06307e2001-07-03 10:35:50 +000010149 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10150 if (URI == NULL) {
10151 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010152 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010153 op->value4, op->value5);
10154 return (total);
10155 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010156 val = xmlXPathVariableLookupNS(ctxt->context,
10157 op->value4, URI);
10158 if (val == NULL) {
10159 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10160 return(0);
10161 }
10162 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010163 }
10164 return (total);
10165 }
10166 case XPATH_OP_FUNCTION:{
10167 xmlXPathFunction func;
10168 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000010169 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010170
10171 if (op->ch1 != -1)
10172 total +=
10173 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010174 if (ctxt->valueNr < op->value) {
10175 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010176 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010177 ctxt->error = XPATH_INVALID_OPERAND;
10178 return (total);
10179 }
10180 for (i = 0; i < op->value; i++)
10181 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10182 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010183 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010184 ctxt->error = XPATH_INVALID_OPERAND;
10185 return (total);
10186 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010187 if (op->cache != NULL)
10188 func = (xmlXPathFunction) op->cache;
10189 else {
10190 const xmlChar *URI = NULL;
10191
10192 if (op->value5 == NULL)
10193 func =
10194 xmlXPathFunctionLookup(ctxt->context,
10195 op->value4);
10196 else {
10197 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10198 if (URI == NULL) {
10199 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010200 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010201 op->value4, op->value5);
10202 return (total);
10203 }
10204 func = xmlXPathFunctionLookupNS(ctxt->context,
10205 op->value4, URI);
10206 }
10207 if (func == NULL) {
10208 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010209 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010210 op->value4);
10211 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010212 }
10213 op->cache = (void *) func;
10214 op->cacheURI = (void *) URI;
10215 }
10216 oldFunc = ctxt->context->function;
10217 oldFuncURI = ctxt->context->functionURI;
10218 ctxt->context->function = op->value4;
10219 ctxt->context->functionURI = op->cacheURI;
10220 func(ctxt, op->value);
10221 ctxt->context->function = oldFunc;
10222 ctxt->context->functionURI = oldFuncURI;
10223 return (total);
10224 }
10225 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000010226 bakd = ctxt->context->doc;
10227 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010228 if (op->ch1 != -1)
10229 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
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 if (op->ch2 != -1)
10234 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010235 ctxt->context->doc = bakd;
10236 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010237 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010238 return (total);
10239 case XPATH_OP_PREDICATE:
10240 case XPATH_OP_FILTER:{
10241 xmlXPathObjectPtr res;
10242 xmlXPathObjectPtr obj, tmp;
10243 xmlNodeSetPtr newset = NULL;
10244 xmlNodeSetPtr oldset;
10245 xmlNodePtr oldnode;
10246 int i;
10247
10248 /*
10249 * Optimization for ()[1] selection i.e. the first elem
10250 */
10251 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10252 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10253 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10254 xmlXPathObjectPtr val;
10255
10256 val = comp->steps[op->ch2].value4;
10257 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10258 (val->floatval == 1.0)) {
10259 xmlNodePtr first = NULL;
10260
10261 total +=
10262 xmlXPathCompOpEvalFirst(ctxt,
10263 &comp->steps[op->ch1],
10264 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010265 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010266 /*
10267 * The nodeset should be in document order,
10268 * Keep only the first value
10269 */
10270 if ((ctxt->value != NULL) &&
10271 (ctxt->value->type == XPATH_NODESET) &&
10272 (ctxt->value->nodesetval != NULL) &&
10273 (ctxt->value->nodesetval->nodeNr > 1))
10274 ctxt->value->nodesetval->nodeNr = 1;
10275 return (total);
10276 }
10277 }
10278 /*
10279 * Optimization for ()[last()] selection i.e. the last elem
10280 */
10281 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10282 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10283 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10284 int f = comp->steps[op->ch2].ch1;
10285
10286 if ((f != -1) &&
10287 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10288 (comp->steps[f].value5 == NULL) &&
10289 (comp->steps[f].value == 0) &&
10290 (comp->steps[f].value4 != NULL) &&
10291 (xmlStrEqual
10292 (comp->steps[f].value4, BAD_CAST "last"))) {
10293 xmlNodePtr last = NULL;
10294
10295 total +=
10296 xmlXPathCompOpEvalLast(ctxt,
10297 &comp->steps[op->ch1],
10298 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010299 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010300 /*
10301 * The nodeset should be in document order,
10302 * Keep only the last value
10303 */
10304 if ((ctxt->value != NULL) &&
10305 (ctxt->value->type == XPATH_NODESET) &&
10306 (ctxt->value->nodesetval != NULL) &&
10307 (ctxt->value->nodesetval->nodeTab != NULL) &&
10308 (ctxt->value->nodesetval->nodeNr > 1)) {
10309 ctxt->value->nodesetval->nodeTab[0] =
10310 ctxt->value->nodesetval->nodeTab[ctxt->
10311 value->
10312 nodesetval->
10313 nodeNr -
10314 1];
10315 ctxt->value->nodesetval->nodeNr = 1;
10316 }
10317 return (total);
10318 }
10319 }
10320
10321 if (op->ch1 != -1)
10322 total +=
10323 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010324 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010325 if (op->ch2 == -1)
10326 return (total);
10327 if (ctxt->value == NULL)
10328 return (total);
10329
10330 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010331
10332#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010333 /*
10334 * Hum are we filtering the result of an XPointer expression
10335 */
10336 if (ctxt->value->type == XPATH_LOCATIONSET) {
10337 xmlLocationSetPtr newlocset = NULL;
10338 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010339
Daniel Veillardf06307e2001-07-03 10:35:50 +000010340 /*
10341 * Extract the old locset, and then evaluate the result of the
10342 * expression for all the element in the locset. use it to grow
10343 * up a new locset.
10344 */
10345 CHECK_TYPE0(XPATH_LOCATIONSET);
10346 obj = valuePop(ctxt);
10347 oldlocset = obj->user;
10348 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010349
Daniel Veillardf06307e2001-07-03 10:35:50 +000010350 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10351 ctxt->context->contextSize = 0;
10352 ctxt->context->proximityPosition = 0;
10353 if (op->ch2 != -1)
10354 total +=
10355 xmlXPathCompOpEval(ctxt,
10356 &comp->steps[op->ch2]);
10357 res = valuePop(ctxt);
10358 if (res != NULL)
10359 xmlXPathFreeObject(res);
10360 valuePush(ctxt, obj);
10361 CHECK_ERROR0;
10362 return (total);
10363 }
10364 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010365
Daniel Veillardf06307e2001-07-03 10:35:50 +000010366 for (i = 0; i < oldlocset->locNr; i++) {
10367 /*
10368 * Run the evaluation with a node list made of a
10369 * single item in the nodelocset.
10370 */
10371 ctxt->context->node = oldlocset->locTab[i]->user;
10372 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10373 valuePush(ctxt, tmp);
10374 ctxt->context->contextSize = oldlocset->locNr;
10375 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010376
Daniel Veillardf06307e2001-07-03 10:35:50 +000010377 if (op->ch2 != -1)
10378 total +=
10379 xmlXPathCompOpEval(ctxt,
10380 &comp->steps[op->ch2]);
10381 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010382
Daniel Veillardf06307e2001-07-03 10:35:50 +000010383 /*
10384 * The result of the evaluation need to be tested to
10385 * decided whether the filter succeeded or not
10386 */
10387 res = valuePop(ctxt);
10388 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10389 xmlXPtrLocationSetAdd(newlocset,
10390 xmlXPathObjectCopy
10391 (oldlocset->locTab[i]));
10392 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010393
Daniel Veillardf06307e2001-07-03 10:35:50 +000010394 /*
10395 * Cleanup
10396 */
10397 if (res != NULL)
10398 xmlXPathFreeObject(res);
10399 if (ctxt->value == tmp) {
10400 res = valuePop(ctxt);
10401 xmlXPathFreeObject(res);
10402 }
10403
10404 ctxt->context->node = NULL;
10405 }
10406
10407 /*
10408 * The result is used as the new evaluation locset.
10409 */
10410 xmlXPathFreeObject(obj);
10411 ctxt->context->node = NULL;
10412 ctxt->context->contextSize = -1;
10413 ctxt->context->proximityPosition = -1;
10414 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10415 ctxt->context->node = oldnode;
10416 return (total);
10417 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010418#endif /* LIBXML_XPTR_ENABLED */
10419
Daniel Veillardf06307e2001-07-03 10:35:50 +000010420 /*
10421 * Extract the old set, and then evaluate the result of the
10422 * expression for all the element in the set. use it to grow
10423 * up a new set.
10424 */
10425 CHECK_TYPE0(XPATH_NODESET);
10426 obj = valuePop(ctxt);
10427 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010428
Daniel Veillardf06307e2001-07-03 10:35:50 +000010429 oldnode = ctxt->context->node;
10430 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010431
Daniel Veillardf06307e2001-07-03 10:35:50 +000010432 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10433 ctxt->context->contextSize = 0;
10434 ctxt->context->proximityPosition = 0;
10435 if (op->ch2 != -1)
10436 total +=
10437 xmlXPathCompOpEval(ctxt,
10438 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010439 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010440 res = valuePop(ctxt);
10441 if (res != NULL)
10442 xmlXPathFreeObject(res);
10443 valuePush(ctxt, obj);
10444 ctxt->context->node = oldnode;
10445 CHECK_ERROR0;
10446 } else {
10447 /*
10448 * Initialize the new set.
10449 */
10450 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010451
Daniel Veillardf06307e2001-07-03 10:35:50 +000010452 for (i = 0; i < oldset->nodeNr; i++) {
10453 /*
10454 * Run the evaluation with a node list made of
10455 * a single item in the nodeset.
10456 */
10457 ctxt->context->node = oldset->nodeTab[i];
10458 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10459 valuePush(ctxt, tmp);
10460 ctxt->context->contextSize = oldset->nodeNr;
10461 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010462
Daniel Veillardf06307e2001-07-03 10:35:50 +000010463 if (op->ch2 != -1)
10464 total +=
10465 xmlXPathCompOpEval(ctxt,
10466 &comp->steps[op->ch2]);
10467 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010468
Daniel Veillardf06307e2001-07-03 10:35:50 +000010469 /*
10470 * The result of the evaluation need to be tested to
10471 * decided whether the filter succeeded or not
10472 */
10473 res = valuePop(ctxt);
10474 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10475 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10476 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010477
Daniel Veillardf06307e2001-07-03 10:35:50 +000010478 /*
10479 * Cleanup
10480 */
10481 if (res != NULL)
10482 xmlXPathFreeObject(res);
10483 if (ctxt->value == tmp) {
10484 res = valuePop(ctxt);
10485 xmlXPathFreeObject(res);
10486 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010487
Daniel Veillardf06307e2001-07-03 10:35:50 +000010488 ctxt->context->node = NULL;
10489 }
10490
10491 /*
10492 * The result is used as the new evaluation set.
10493 */
10494 xmlXPathFreeObject(obj);
10495 ctxt->context->node = NULL;
10496 ctxt->context->contextSize = -1;
10497 ctxt->context->proximityPosition = -1;
10498 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10499 }
10500 ctxt->context->node = oldnode;
10501 return (total);
10502 }
10503 case XPATH_OP_SORT:
10504 if (op->ch1 != -1)
10505 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010506 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010507 if ((ctxt->value != NULL) &&
10508 (ctxt->value->type == XPATH_NODESET) &&
10509 (ctxt->value->nodesetval != NULL))
10510 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10511 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010512#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010513 case XPATH_OP_RANGETO:{
10514 xmlXPathObjectPtr range;
10515 xmlXPathObjectPtr res, obj;
10516 xmlXPathObjectPtr tmp;
10517 xmlLocationSetPtr newset = NULL;
10518 xmlNodeSetPtr oldset;
10519 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010520
Daniel Veillardf06307e2001-07-03 10:35:50 +000010521 if (op->ch1 != -1)
10522 total +=
10523 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10524 if (op->ch2 == -1)
10525 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010526
Daniel Veillardf06307e2001-07-03 10:35:50 +000010527 CHECK_TYPE0(XPATH_NODESET);
10528 obj = valuePop(ctxt);
10529 oldset = obj->nodesetval;
10530 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010531
Daniel Veillardf06307e2001-07-03 10:35:50 +000010532 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010533
Daniel Veillardf06307e2001-07-03 10:35:50 +000010534 if (oldset != NULL) {
10535 for (i = 0; i < oldset->nodeNr; i++) {
10536 /*
10537 * Run the evaluation with a node list made of a single item
10538 * in the nodeset.
10539 */
10540 ctxt->context->node = oldset->nodeTab[i];
10541 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10542 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010543
Daniel Veillardf06307e2001-07-03 10:35:50 +000010544 if (op->ch2 != -1)
10545 total +=
10546 xmlXPathCompOpEval(ctxt,
10547 &comp->steps[op->ch2]);
10548 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010549
Daniel Veillardf06307e2001-07-03 10:35:50 +000010550 /*
10551 * The result of the evaluation need to be tested to
10552 * decided whether the filter succeeded or not
10553 */
10554 res = valuePop(ctxt);
10555 range =
10556 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10557 res);
10558 if (range != NULL) {
10559 xmlXPtrLocationSetAdd(newset, range);
10560 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010561
Daniel Veillardf06307e2001-07-03 10:35:50 +000010562 /*
10563 * Cleanup
10564 */
10565 if (res != NULL)
10566 xmlXPathFreeObject(res);
10567 if (ctxt->value == tmp) {
10568 res = valuePop(ctxt);
10569 xmlXPathFreeObject(res);
10570 }
10571
10572 ctxt->context->node = NULL;
10573 }
10574 }
10575
10576 /*
10577 * The result is used as the new evaluation set.
10578 */
10579 xmlXPathFreeObject(obj);
10580 ctxt->context->node = NULL;
10581 ctxt->context->contextSize = -1;
10582 ctxt->context->proximityPosition = -1;
10583 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
10584 return (total);
10585 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010586#endif /* LIBXML_XPTR_ENABLED */
10587 }
10588 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010589 "XPath: unknown precompiled operation %d\n", op->op);
10590 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010591}
10592
10593/**
10594 * xmlXPathRunEval:
10595 * @ctxt: the XPath parser context with the compiled expression
10596 *
10597 * Evaluate the Precompiled XPath expression in the given context.
10598 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010599static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010600xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10601 xmlXPathCompExprPtr comp;
10602
10603 if ((ctxt == NULL) || (ctxt->comp == NULL))
10604 return;
10605
10606 if (ctxt->valueTab == NULL) {
10607 /* Allocate the value stack */
10608 ctxt->valueTab = (xmlXPathObjectPtr *)
10609 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10610 if (ctxt->valueTab == NULL) {
10611 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010612 }
10613 ctxt->valueNr = 0;
10614 ctxt->valueMax = 10;
10615 ctxt->value = NULL;
10616 }
10617 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000010618 if(comp->last < 0) {
10619 xmlGenericError(xmlGenericErrorContext,
10620 "xmlXPathRunEval: last is less than zero\n");
10621 return;
10622 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010623 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10624}
10625
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010626/************************************************************************
10627 * *
10628 * Public interfaces *
10629 * *
10630 ************************************************************************/
10631
10632/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010633 * xmlXPathEvalPredicate:
10634 * @ctxt: the XPath context
10635 * @res: the Predicate Expression evaluation result
10636 *
10637 * Evaluate a predicate result for the current node.
10638 * A PredicateExpr is evaluated by evaluating the Expr and converting
10639 * the result to a boolean. If the result is a number, the result will
10640 * be converted to true if the number is equal to the position of the
10641 * context node in the context node list (as returned by the position
10642 * function) and will be converted to false otherwise; if the result
10643 * is not a number, then the result will be converted as if by a call
10644 * to the boolean function.
10645 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010646 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010647 */
10648int
10649xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
10650 if (res == NULL) return(0);
10651 switch (res->type) {
10652 case XPATH_BOOLEAN:
10653 return(res->boolval);
10654 case XPATH_NUMBER:
10655 return(res->floatval == ctxt->proximityPosition);
10656 case XPATH_NODESET:
10657 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010658 if (res->nodesetval == NULL)
10659 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010660 return(res->nodesetval->nodeNr != 0);
10661 case XPATH_STRING:
10662 return((res->stringval != NULL) &&
10663 (xmlStrlen(res->stringval) != 0));
10664 default:
10665 STRANGE
10666 }
10667 return(0);
10668}
10669
10670/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010671 * xmlXPathEvaluatePredicateResult:
10672 * @ctxt: the XPath Parser context
10673 * @res: the Predicate Expression evaluation result
10674 *
10675 * Evaluate a predicate result for the current node.
10676 * A PredicateExpr is evaluated by evaluating the Expr and converting
10677 * the result to a boolean. If the result is a number, the result will
10678 * be converted to true if the number is equal to the position of the
10679 * context node in the context node list (as returned by the position
10680 * function) and will be converted to false otherwise; if the result
10681 * is not a number, then the result will be converted as if by a call
10682 * to the boolean function.
10683 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010684 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010685 */
10686int
10687xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10688 xmlXPathObjectPtr res) {
10689 if (res == NULL) return(0);
10690 switch (res->type) {
10691 case XPATH_BOOLEAN:
10692 return(res->boolval);
10693 case XPATH_NUMBER:
10694 return(res->floatval == ctxt->context->proximityPosition);
10695 case XPATH_NODESET:
10696 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000010697 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000010698 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010699 return(res->nodesetval->nodeNr != 0);
10700 case XPATH_STRING:
10701 return((res->stringval != NULL) &&
10702 (xmlStrlen(res->stringval) != 0));
10703 default:
10704 STRANGE
10705 }
10706 return(0);
10707}
10708
10709/**
10710 * xmlXPathCompile:
10711 * @str: the XPath expression
10712 *
10713 * Compile an XPath expression
10714 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000010715 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010716 * the caller has to free the object.
10717 */
10718xmlXPathCompExprPtr
10719xmlXPathCompile(const xmlChar *str) {
10720 xmlXPathParserContextPtr ctxt;
10721 xmlXPathCompExprPtr comp;
10722
10723 xmlXPathInit();
10724
10725 ctxt = xmlXPathNewParserContext(str, NULL);
10726 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010727
Daniel Veillard40af6492001-04-22 08:50:55 +000010728 if (*ctxt->cur != 0) {
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010729 /*
10730 * aleksey: in some cases this line prints *second* error message
10731 * (see bug #78858) and probably this should be fixed.
10732 * However, we are not sure that all error messages are printed
10733 * out in other places. It's not critical so we leave it as-is for now
10734 */
Daniel Veillard40af6492001-04-22 08:50:55 +000010735 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10736 comp = NULL;
10737 } else {
10738 comp = ctxt->comp;
10739 ctxt->comp = NULL;
10740 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010741 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010742 if (comp != NULL) {
Daniel Veillardceb09b92002-10-04 11:46:37 +000010743 comp->expr = xmlStrdup(str);
10744#ifdef DEBUG_EVAL_COUNTS
Daniel Veillardf06307e2001-07-03 10:35:50 +000010745 comp->string = xmlStrdup(str);
10746 comp->nb = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010747#endif
Daniel Veillardceb09b92002-10-04 11:46:37 +000010748 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010749 return(comp);
10750}
10751
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010752/**
10753 * xmlXPathCompiledEval:
10754 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000010755 * @ctx: the XPath context
10756 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010757 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000010758 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010759 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000010760 * the caller has to free the object.
10761 */
10762xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010763xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000010764 xmlXPathParserContextPtr ctxt;
10765 xmlXPathObjectPtr res, tmp, init = NULL;
10766 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000010767#ifndef LIBXML_THREAD_ENABLED
10768 static int reentance = 0;
10769#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010770
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010771 if ((comp == NULL) || (ctx == NULL))
10772 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010773 xmlXPathInit();
10774
10775 CHECK_CONTEXT(ctx)
10776
Daniel Veillard81463942001-10-16 12:34:39 +000010777#ifndef LIBXML_THREAD_ENABLED
10778 reentance++;
10779 if (reentance > 1)
10780 xmlXPathDisableOptimizer = 1;
10781#endif
10782
Daniel Veillardf06307e2001-07-03 10:35:50 +000010783#ifdef DEBUG_EVAL_COUNTS
10784 comp->nb++;
10785 if ((comp->string != NULL) && (comp->nb > 100)) {
10786 fprintf(stderr, "100 x %s\n", comp->string);
10787 comp->nb = 0;
10788 }
10789#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010790 ctxt = xmlXPathCompParserContext(comp, ctx);
10791 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010792
10793 if (ctxt->value == NULL) {
10794 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010795 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000010796 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000010797 } else {
10798 res = valuePop(ctxt);
10799 }
10800
Daniel Veillardf06307e2001-07-03 10:35:50 +000010801
Owen Taylor3473f882001-02-23 17:55:21 +000010802 do {
10803 tmp = valuePop(ctxt);
10804 if (tmp != NULL) {
10805 if (tmp != init)
10806 stack++;
10807 xmlXPathFreeObject(tmp);
10808 }
10809 } while (tmp != NULL);
10810 if ((stack != 0) && (res != NULL)) {
10811 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010812 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000010813 stack);
10814 }
10815 if (ctxt->error != XPATH_EXPRESSION_OK) {
10816 xmlXPathFreeObject(res);
10817 res = NULL;
10818 }
10819
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010820
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010821 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010822 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000010823#ifndef LIBXML_THREAD_ENABLED
10824 reentance--;
10825#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010826 return(res);
10827}
10828
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010829/**
10830 * xmlXPathEvalExpr:
10831 * @ctxt: the XPath Parser context
10832 *
10833 * Parse and evaluate an XPath expression in the given context,
10834 * then push the result on the context stack
10835 */
10836void
10837xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
10838 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010839 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010840 xmlXPathRunEval(ctxt);
10841}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010842
10843/**
10844 * xmlXPathEval:
10845 * @str: the XPath expression
10846 * @ctx: the XPath context
10847 *
10848 * Evaluate the XPath Location Path in the given context.
10849 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010850 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010851 * the caller has to free the object.
10852 */
10853xmlXPathObjectPtr
10854xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
10855 xmlXPathParserContextPtr ctxt;
10856 xmlXPathObjectPtr res, tmp, init = NULL;
10857 int stack = 0;
10858
10859 xmlXPathInit();
10860
10861 CHECK_CONTEXT(ctx)
10862
10863 ctxt = xmlXPathNewParserContext(str, ctx);
10864 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010865
10866 if (ctxt->value == NULL) {
10867 xmlGenericError(xmlGenericErrorContext,
10868 "xmlXPathEval: evaluation failed\n");
10869 res = NULL;
10870 } else if (*ctxt->cur != 0) {
10871 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10872 res = NULL;
10873 } else {
10874 res = valuePop(ctxt);
10875 }
10876
10877 do {
10878 tmp = valuePop(ctxt);
10879 if (tmp != NULL) {
10880 if (tmp != init)
10881 stack++;
10882 xmlXPathFreeObject(tmp);
10883 }
10884 } while (tmp != NULL);
10885 if ((stack != 0) && (res != NULL)) {
10886 xmlGenericError(xmlGenericErrorContext,
10887 "xmlXPathEval: %d object left on the stack\n",
10888 stack);
10889 }
10890 if (ctxt->error != XPATH_EXPRESSION_OK) {
10891 xmlXPathFreeObject(res);
10892 res = NULL;
10893 }
10894
Owen Taylor3473f882001-02-23 17:55:21 +000010895 xmlXPathFreeParserContext(ctxt);
10896 return(res);
10897}
10898
10899/**
10900 * xmlXPathEvalExpression:
10901 * @str: the XPath expression
10902 * @ctxt: the XPath context
10903 *
10904 * Evaluate the XPath expression in the given context.
10905 *
10906 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
10907 * the caller has to free the object.
10908 */
10909xmlXPathObjectPtr
10910xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
10911 xmlXPathParserContextPtr pctxt;
10912 xmlXPathObjectPtr res, tmp;
10913 int stack = 0;
10914
10915 xmlXPathInit();
10916
10917 CHECK_CONTEXT(ctxt)
10918
10919 pctxt = xmlXPathNewParserContext(str, ctxt);
10920 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010921
10922 if (*pctxt->cur != 0) {
10923 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10924 res = NULL;
10925 } else {
10926 res = valuePop(pctxt);
10927 }
10928 do {
10929 tmp = valuePop(pctxt);
10930 if (tmp != NULL) {
10931 xmlXPathFreeObject(tmp);
10932 stack++;
10933 }
10934 } while (tmp != NULL);
10935 if ((stack != 0) && (res != NULL)) {
10936 xmlGenericError(xmlGenericErrorContext,
10937 "xmlXPathEvalExpression: %d object left on the stack\n",
10938 stack);
10939 }
10940 xmlXPathFreeParserContext(pctxt);
10941 return(res);
10942}
10943
Daniel Veillard42766c02002-08-22 20:52:17 +000010944/************************************************************************
10945 * *
10946 * Extra functions not pertaining to the XPath spec *
10947 * *
10948 ************************************************************************/
10949/**
10950 * xmlXPathEscapeUriFunction:
10951 * @ctxt: the XPath Parser context
10952 * @nargs: the number of arguments
10953 *
10954 * Implement the escape-uri() XPath function
10955 * string escape-uri(string $str, bool $escape-reserved)
10956 *
10957 * This function applies the URI escaping rules defined in section 2 of [RFC
10958 * 2396] to the string supplied as $uri-part, which typically represents all
10959 * or part of a URI. The effect of the function is to replace any special
10960 * character in the string by an escape sequence of the form %xx%yy...,
10961 * where xxyy... is the hexadecimal representation of the octets used to
10962 * represent the character in UTF-8.
10963 *
10964 * The set of characters that are escaped depends on the setting of the
10965 * boolean argument $escape-reserved.
10966 *
10967 * If $escape-reserved is true, all characters are escaped other than lower
10968 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
10969 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
10970 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
10971 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
10972 * A-F).
10973 *
10974 * If $escape-reserved is false, the behavior differs in that characters
10975 * referred to in [RFC 2396] as reserved characters are not escaped. These
10976 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
10977 *
10978 * [RFC 2396] does not define whether escaped URIs should use lower case or
10979 * upper case for hexadecimal digits. To ensure that escaped URIs can be
10980 * compared using string comparison functions, this function must always use
10981 * the upper-case letters A-F.
10982 *
10983 * Generally, $escape-reserved should be set to true when escaping a string
10984 * that is to form a single part of a URI, and to false when escaping an
10985 * entire URI or URI reference.
10986 *
10987 * In the case of non-ascii characters, the string is encoded according to
10988 * utf-8 and then converted according to RFC 2396.
10989 *
10990 * Examples
10991 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
10992 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
10993 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
10994 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
10995 *
10996 */
Daniel Veillard118aed72002-09-24 14:13:13 +000010997static void
Daniel Veillard42766c02002-08-22 20:52:17 +000010998xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
10999 xmlXPathObjectPtr str;
11000 int escape_reserved;
11001 xmlBufferPtr target;
11002 xmlChar *cptr;
11003 xmlChar escape[4];
11004
11005 CHECK_ARITY(2);
11006
11007 escape_reserved = xmlXPathPopBoolean(ctxt);
11008
11009 CAST_TO_STRING;
11010 str = valuePop(ctxt);
11011
11012 target = xmlBufferCreate();
11013
11014 escape[0] = '%';
11015 escape[3] = 0;
11016
11017 if (target) {
11018 for (cptr = str->stringval; *cptr; cptr++) {
11019 if ((*cptr >= 'A' && *cptr <= 'Z') ||
11020 (*cptr >= 'a' && *cptr <= 'z') ||
11021 (*cptr >= '0' && *cptr <= '9') ||
11022 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
11023 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
11024 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
11025 (*cptr == '%' &&
11026 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
11027 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
11028 (cptr[1] >= '0' && cptr[1] <= '9')) &&
11029 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
11030 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
11031 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
11032 (!escape_reserved &&
11033 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
11034 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
11035 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
11036 *cptr == ','))) {
11037 xmlBufferAdd(target, cptr, 1);
11038 } else {
11039 if ((*cptr >> 4) < 10)
11040 escape[1] = '0' + (*cptr >> 4);
11041 else
11042 escape[1] = 'A' - 10 + (*cptr >> 4);
11043 if ((*cptr & 0xF) < 10)
11044 escape[2] = '0' + (*cptr & 0xF);
11045 else
11046 escape[2] = 'A' - 10 + (*cptr & 0xF);
11047
11048 xmlBufferAdd(target, &escape[0], 3);
11049 }
11050 }
11051 }
11052 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
11053 xmlBufferFree(target);
11054 xmlXPathFreeObject(str);
11055}
11056
Owen Taylor3473f882001-02-23 17:55:21 +000011057/**
11058 * xmlXPathRegisterAllFunctions:
11059 * @ctxt: the XPath context
11060 *
11061 * Registers all default XPath functions in this context
11062 */
11063void
11064xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
11065{
11066 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
11067 xmlXPathBooleanFunction);
11068 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
11069 xmlXPathCeilingFunction);
11070 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
11071 xmlXPathCountFunction);
11072 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
11073 xmlXPathConcatFunction);
11074 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
11075 xmlXPathContainsFunction);
11076 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
11077 xmlXPathIdFunction);
11078 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
11079 xmlXPathFalseFunction);
11080 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
11081 xmlXPathFloorFunction);
11082 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
11083 xmlXPathLastFunction);
11084 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
11085 xmlXPathLangFunction);
11086 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
11087 xmlXPathLocalNameFunction);
11088 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
11089 xmlXPathNotFunction);
11090 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
11091 xmlXPathNameFunction);
11092 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
11093 xmlXPathNamespaceURIFunction);
11094 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
11095 xmlXPathNormalizeFunction);
11096 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
11097 xmlXPathNumberFunction);
11098 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
11099 xmlXPathPositionFunction);
11100 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
11101 xmlXPathRoundFunction);
11102 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
11103 xmlXPathStringFunction);
11104 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
11105 xmlXPathStringLengthFunction);
11106 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
11107 xmlXPathStartsWithFunction);
11108 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
11109 xmlXPathSubstringFunction);
11110 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
11111 xmlXPathSubstringBeforeFunction);
11112 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
11113 xmlXPathSubstringAfterFunction);
11114 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
11115 xmlXPathSumFunction);
11116 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
11117 xmlXPathTrueFunction);
11118 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
11119 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000011120
11121 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
11122 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
11123 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000011124}
11125
11126#endif /* LIBXML_XPATH_ENABLED */