blob: 92d68de73c33acf7d116934f6a1c0489c1eb9ec7 [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 Veillard9e7160d2001-03-18 23:17:47 +000055/************************************************************************
56 * *
57 * Floating point stuff *
58 * *
59 ************************************************************************/
60
Daniel Veillardc0631a62001-09-20 13:56:06 +000061#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +000062#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +000063#endif
Daniel Veillardcda96922001-08-21 10:56:31 +000064#include "trionan.c"
65
Owen Taylor3473f882001-02-23 17:55:21 +000066/*
Owen Taylor3473f882001-02-23 17:55:21 +000067 * The lack of portability of this section of the libc is annoying !
68 */
69double xmlXPathNAN = 0;
70double xmlXPathPINF = 1;
71double xmlXPathNINF = -1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +000072double xmlXPathNZERO = 0;
Daniel Veillard20ee8c02001-10-05 09:18:14 +000073static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000074
Owen Taylor3473f882001-02-23 17:55:21 +000075/**
76 * xmlXPathInit:
77 *
78 * Initialize the XPath environment
79 */
80void
81xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +000082 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +000083
Bjorn Reese45029602001-08-21 09:23:53 +000084 xmlXPathPINF = trio_pinf();
85 xmlXPathNINF = trio_ninf();
86 xmlXPathNAN = trio_nan();
Daniel Veillard5fc1f082002-03-27 09:05:40 +000087 xmlXPathNZERO = trio_nzero();
Owen Taylor3473f882001-02-23 17:55:21 +000088
Daniel Veillard20ee8c02001-10-05 09:18:14 +000089 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000090}
91
Daniel Veillardcda96922001-08-21 10:56:31 +000092/**
93 * xmlXPathIsNaN:
94 * @val: a double value
95 *
96 * Provides a portable isnan() function to detect whether a double
97 * is a NotaNumber. Based on trio code
98 * http://sourceforge.net/projects/ctrio/
99 *
100 * Returns 1 if the value is a NaN, 0 otherwise
101 */
102int
103xmlXPathIsNaN(double val) {
104 return(trio_isnan(val));
105}
106
107/**
108 * xmlXPathIsInf:
109 * @val: a double value
110 *
111 * Provides a portable isinf() function to detect whether a double
112 * is a +Infinite or -Infinite. Based on trio code
113 * http://sourceforge.net/projects/ctrio/
114 *
115 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
116 */
117int
118xmlXPathIsInf(double val) {
119 return(trio_isinf(val));
120}
121
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000122/**
123 * xmlXPathGetSign:
124 * @val: a double value
125 *
126 * Provides a portable function to detect the sign of a double
127 * Modified from trio code
128 * http://sourceforge.net/projects/ctrio/
129 *
130 * Returns 1 if the value is Negative, 0 if positive
131 */
Daniel Veillard21458c82002-03-27 16:12:22 +0000132static int
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000133xmlXPathGetSign(double val) {
Daniel Veillard21458c82002-03-27 16:12:22 +0000134 return(trio_signbit(val));
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000135}
136
137
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000138#ifdef LIBXML_XPATH_ENABLED
139/*
140 * TODO: when compatibility allows remove all "fake node libxslt" strings
141 * the test should just be name[0] = ' '
142 */
143/* #define DEBUG */
144/* #define DEBUG_STEP */
145/* #define DEBUG_STEP_NTH */
146/* #define DEBUG_EXPR */
147/* #define DEBUG_EVAL_COUNTS */
148
149static xmlNs xmlXPathXMLNamespaceStruct = {
150 NULL,
151 XML_NAMESPACE_DECL,
152 XML_XML_NAMESPACE,
153 BAD_CAST "xml",
154 NULL
155};
156static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
157#ifndef LIBXML_THREAD_ENABLED
158/*
159 * Optimizer is disabled only when threaded apps are detected while
160 * the library ain't compiled for thread safety.
161 */
162static int xmlXPathDisableOptimizer = 0;
163#endif
164
Owen Taylor3473f882001-02-23 17:55:21 +0000165/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000166 * *
167 * Parser Types *
168 * *
169 ************************************************************************/
170
171/*
172 * Types are private:
173 */
174
175typedef enum {
176 XPATH_OP_END=0,
177 XPATH_OP_AND,
178 XPATH_OP_OR,
179 XPATH_OP_EQUAL,
180 XPATH_OP_CMP,
181 XPATH_OP_PLUS,
182 XPATH_OP_MULT,
183 XPATH_OP_UNION,
184 XPATH_OP_ROOT,
185 XPATH_OP_NODE,
186 XPATH_OP_RESET,
187 XPATH_OP_COLLECT,
188 XPATH_OP_VALUE,
189 XPATH_OP_VARIABLE,
190 XPATH_OP_FUNCTION,
191 XPATH_OP_ARG,
192 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000193 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000194 XPATH_OP_SORT
195#ifdef LIBXML_XPTR_ENABLED
196 ,XPATH_OP_RANGETO
197#endif
198} xmlXPathOp;
199
200typedef enum {
201 AXIS_ANCESTOR = 1,
202 AXIS_ANCESTOR_OR_SELF,
203 AXIS_ATTRIBUTE,
204 AXIS_CHILD,
205 AXIS_DESCENDANT,
206 AXIS_DESCENDANT_OR_SELF,
207 AXIS_FOLLOWING,
208 AXIS_FOLLOWING_SIBLING,
209 AXIS_NAMESPACE,
210 AXIS_PARENT,
211 AXIS_PRECEDING,
212 AXIS_PRECEDING_SIBLING,
213 AXIS_SELF
214} xmlXPathAxisVal;
215
216typedef enum {
217 NODE_TEST_NONE = 0,
218 NODE_TEST_TYPE = 1,
219 NODE_TEST_PI = 2,
220 NODE_TEST_ALL = 3,
221 NODE_TEST_NS = 4,
222 NODE_TEST_NAME = 5
223} xmlXPathTestVal;
224
225typedef enum {
226 NODE_TYPE_NODE = 0,
227 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
228 NODE_TYPE_TEXT = XML_TEXT_NODE,
229 NODE_TYPE_PI = XML_PI_NODE
230} xmlXPathTypeVal;
231
232
233typedef struct _xmlXPathStepOp xmlXPathStepOp;
234typedef xmlXPathStepOp *xmlXPathStepOpPtr;
235struct _xmlXPathStepOp {
236 xmlXPathOp op;
237 int ch1;
238 int ch2;
239 int value;
240 int value2;
241 int value3;
242 void *value4;
243 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000244 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000245 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000246};
247
248struct _xmlXPathCompExpr {
249 int nbStep;
250 int maxStep;
251 xmlXPathStepOp *steps; /* ops for computation */
252 int last;
Daniel Veillard118aed72002-09-24 14:13:13 +0000253 xmlChar *expr;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000254#ifdef DEBUG_EVAL_COUNTS
255 int nb;
256 xmlChar *string;
257#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000258};
259
260/************************************************************************
261 * *
262 * Parser Type functions *
263 * *
264 ************************************************************************/
265
266/**
267 * xmlXPathNewCompExpr:
268 *
269 * Create a new Xpath component
270 *
271 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
272 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000273static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000274xmlXPathNewCompExpr(void) {
275 xmlXPathCompExprPtr cur;
276
277 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
278 if (cur == NULL) {
279 xmlGenericError(xmlGenericErrorContext,
280 "xmlXPathNewCompExpr : malloc failed\n");
281 return(NULL);
282 }
283 memset(cur, 0, sizeof(xmlXPathCompExpr));
284 cur->maxStep = 10;
285 cur->nbStep = 0;
286 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
287 sizeof(xmlXPathStepOp));
288 if (cur->steps == NULL) {
289 xmlGenericError(xmlGenericErrorContext,
290 "xmlXPathNewCompExpr : malloc failed\n");
291 xmlFree(cur);
292 return(NULL);
293 }
294 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
295 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000296#ifdef DEBUG_EVAL_COUNTS
297 cur->nb = 0;
298#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000299 return(cur);
300}
301
302/**
303 * xmlXPathFreeCompExpr:
304 * @comp: an XPATH comp
305 *
306 * Free up the memory allocated by @comp
307 */
308void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000309xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
310{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000311 xmlXPathStepOpPtr op;
312 int i;
313
314 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000315 return;
316 for (i = 0; i < comp->nbStep; i++) {
317 op = &comp->steps[i];
318 if (op->value4 != NULL) {
319 if (op->op == XPATH_OP_VALUE)
320 xmlXPathFreeObject(op->value4);
321 else
322 xmlFree(op->value4);
323 }
324 if (op->value5 != NULL)
325 xmlFree(op->value5);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000326 }
327 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000328 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000329 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000330#ifdef DEBUG_EVAL_COUNTS
331 if (comp->string != NULL) {
332 xmlFree(comp->string);
333 }
334#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000335 if (comp->expr != NULL) {
336 xmlFree(comp->expr);
337 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000338
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000339 xmlFree(comp);
340}
341
342/**
343 * xmlXPathCompExprAdd:
344 * @comp: the compiled expression
345 * @ch1: first child index
346 * @ch2: second child index
347 * @op: an op
348 * @value: the first int value
349 * @value2: the second int value
350 * @value3: the third int value
351 * @value4: the first string value
352 * @value5: the second string value
353 *
354 * Add an step to an XPath Compiled Expression
355 *
356 * Returns -1 in case of failure, the index otherwise
357 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000358static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000359xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
360 xmlXPathOp op, int value,
361 int value2, int value3, void *value4, void *value5) {
362 if (comp->nbStep >= comp->maxStep) {
363 xmlXPathStepOp *real;
364
365 comp->maxStep *= 2;
366 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
367 comp->maxStep * sizeof(xmlXPathStepOp));
368 if (real == NULL) {
369 comp->maxStep /= 2;
370 xmlGenericError(xmlGenericErrorContext,
371 "xmlXPathCompExprAdd : realloc failed\n");
372 return(-1);
373 }
374 comp->steps = real;
375 }
376 comp->last = comp->nbStep;
377 comp->steps[comp->nbStep].ch1 = ch1;
378 comp->steps[comp->nbStep].ch2 = ch2;
379 comp->steps[comp->nbStep].op = op;
380 comp->steps[comp->nbStep].value = value;
381 comp->steps[comp->nbStep].value2 = value2;
382 comp->steps[comp->nbStep].value3 = value3;
383 comp->steps[comp->nbStep].value4 = value4;
384 comp->steps[comp->nbStep].value5 = value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000385 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000386 return(comp->nbStep++);
387}
388
Daniel Veillardf06307e2001-07-03 10:35:50 +0000389/**
390 * xmlXPathCompSwap:
391 * @comp: the compiled expression
392 * @op: operation index
393 *
394 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000395 */
396static void
397xmlXPathCompSwap(xmlXPathStepOpPtr op) {
398 int tmp;
399
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000400#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000401 /*
402 * Since this manipulates possibly shared variables, this is
403 * disable if one detects that the library is used in a multithreaded
404 * application
405 */
406 if (xmlXPathDisableOptimizer)
407 return;
408#endif
409
Daniel Veillardf06307e2001-07-03 10:35:50 +0000410 tmp = op->ch1;
411 op->ch1 = op->ch2;
412 op->ch2 = tmp;
413}
414
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000415#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
416 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
417 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000418#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
419 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
420 (op), (val), (val2), (val3), (val4), (val5))
421
422#define PUSH_LEAVE_EXPR(op, val, val2) \
423xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
424
425#define PUSH_UNARY_EXPR(op, ch, val, val2) \
426xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
427
428#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
429xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), (val), (val2), 0 ,NULL ,NULL)
430
431/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000432 * *
433 * Debugging related functions *
434 * *
435 ************************************************************************/
436
437#define TODO \
438 xmlGenericError(xmlGenericErrorContext, \
439 "Unimplemented block at %s:%d\n", \
440 __FILE__, __LINE__);
441
442#define STRANGE \
443 xmlGenericError(xmlGenericErrorContext, \
444 "Internal error at %s:%d\n", \
445 __FILE__, __LINE__);
446
447#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000448static void
449xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000450 int i;
451 char shift[100];
452
453 for (i = 0;((i < depth) && (i < 25));i++)
454 shift[2 * i] = shift[2 * i + 1] = ' ';
455 shift[2 * i] = shift[2 * i + 1] = 0;
456 if (cur == NULL) {
457 fprintf(output, shift);
458 fprintf(output, "Node is NULL !\n");
459 return;
460
461 }
462
463 if ((cur->type == XML_DOCUMENT_NODE) ||
464 (cur->type == XML_HTML_DOCUMENT_NODE)) {
465 fprintf(output, shift);
466 fprintf(output, " /\n");
467 } else if (cur->type == XML_ATTRIBUTE_NODE)
468 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
469 else
470 xmlDebugDumpOneNode(output, cur, depth);
471}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000472static void
473xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000474 xmlNodePtr tmp;
475 int i;
476 char shift[100];
477
478 for (i = 0;((i < depth) && (i < 25));i++)
479 shift[2 * i] = shift[2 * i + 1] = ' ';
480 shift[2 * i] = shift[2 * i + 1] = 0;
481 if (cur == NULL) {
482 fprintf(output, shift);
483 fprintf(output, "Node is NULL !\n");
484 return;
485
486 }
487
488 while (cur != NULL) {
489 tmp = cur;
490 cur = cur->next;
491 xmlDebugDumpOneNode(output, tmp, depth);
492 }
493}
Owen Taylor3473f882001-02-23 17:55:21 +0000494
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000495static void
496xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000497 int i;
498 char shift[100];
499
500 for (i = 0;((i < depth) && (i < 25));i++)
501 shift[2 * i] = shift[2 * i + 1] = ' ';
502 shift[2 * i] = shift[2 * i + 1] = 0;
503
504 if (cur == NULL) {
505 fprintf(output, shift);
506 fprintf(output, "NodeSet is NULL !\n");
507 return;
508
509 }
510
Daniel Veillard911f49a2001-04-07 15:39:35 +0000511 if (cur != NULL) {
512 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
513 for (i = 0;i < cur->nodeNr;i++) {
514 fprintf(output, shift);
515 fprintf(output, "%d", i + 1);
516 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
517 }
Owen Taylor3473f882001-02-23 17:55:21 +0000518 }
519}
520
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000521static void
522xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000523 int i;
524 char shift[100];
525
526 for (i = 0;((i < depth) && (i < 25));i++)
527 shift[2 * i] = shift[2 * i + 1] = ' ';
528 shift[2 * i] = shift[2 * i + 1] = 0;
529
530 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
531 fprintf(output, shift);
532 fprintf(output, "Value Tree is NULL !\n");
533 return;
534
535 }
536
537 fprintf(output, shift);
538 fprintf(output, "%d", i + 1);
539 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
540}
Owen Taylor3473f882001-02-23 17:55:21 +0000541#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000542static void
543xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000544 int i;
545 char shift[100];
546
547 for (i = 0;((i < depth) && (i < 25));i++)
548 shift[2 * i] = shift[2 * i + 1] = ' ';
549 shift[2 * i] = shift[2 * i + 1] = 0;
550
551 if (cur == NULL) {
552 fprintf(output, shift);
553 fprintf(output, "LocationSet is NULL !\n");
554 return;
555
556 }
557
558 for (i = 0;i < cur->locNr;i++) {
559 fprintf(output, shift);
560 fprintf(output, "%d : ", i + 1);
561 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
562 }
563}
Daniel Veillard017b1082001-06-21 11:20:21 +0000564#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000565
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000566/**
567 * xmlXPathDebugDumpObject:
568 * @output: the FILE * to dump the output
569 * @cur: the object to inspect
570 * @depth: indentation level
571 *
572 * Dump the content of the object for debugging purposes
573 */
574void
575xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000576 int i;
577 char shift[100];
578
579 for (i = 0;((i < depth) && (i < 25));i++)
580 shift[2 * i] = shift[2 * i + 1] = ' ';
581 shift[2 * i] = shift[2 * i + 1] = 0;
582
583 fprintf(output, shift);
584
585 if (cur == NULL) {
586 fprintf(output, "Object is empty (NULL)\n");
587 return;
588 }
589 switch(cur->type) {
590 case XPATH_UNDEFINED:
591 fprintf(output, "Object is uninitialized\n");
592 break;
593 case XPATH_NODESET:
594 fprintf(output, "Object is a Node Set :\n");
595 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
596 break;
597 case XPATH_XSLT_TREE:
598 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000599 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000600 break;
601 case XPATH_BOOLEAN:
602 fprintf(output, "Object is a Boolean : ");
603 if (cur->boolval) fprintf(output, "true\n");
604 else fprintf(output, "false\n");
605 break;
606 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +0000607 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000608 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000609 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000610 break;
611 case -1:
612 fprintf(output, "Object is a number : -Infinity\n");
613 break;
614 default:
Daniel Veillardcda96922001-08-21 10:56:31 +0000615 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000616 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +0000617 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
618 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000619 } else {
620 fprintf(output, "Object is a number : %0g\n", cur->floatval);
621 }
622 }
Owen Taylor3473f882001-02-23 17:55:21 +0000623 break;
624 case XPATH_STRING:
625 fprintf(output, "Object is a string : ");
626 xmlDebugDumpString(output, cur->stringval);
627 fprintf(output, "\n");
628 break;
629 case XPATH_POINT:
630 fprintf(output, "Object is a point : index %d in node", cur->index);
631 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
632 fprintf(output, "\n");
633 break;
634 case XPATH_RANGE:
635 if ((cur->user2 == NULL) ||
636 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
637 fprintf(output, "Object is a collapsed range :\n");
638 fprintf(output, shift);
639 if (cur->index >= 0)
640 fprintf(output, "index %d in ", cur->index);
641 fprintf(output, "node\n");
642 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
643 depth + 1);
644 } else {
645 fprintf(output, "Object is a range :\n");
646 fprintf(output, shift);
647 fprintf(output, "From ");
648 if (cur->index >= 0)
649 fprintf(output, "index %d in ", cur->index);
650 fprintf(output, "node\n");
651 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
652 depth + 1);
653 fprintf(output, shift);
654 fprintf(output, "To ");
655 if (cur->index2 >= 0)
656 fprintf(output, "index %d in ", cur->index2);
657 fprintf(output, "node\n");
658 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
659 depth + 1);
660 fprintf(output, "\n");
661 }
662 break;
663 case XPATH_LOCATIONSET:
664#if defined(LIBXML_XPTR_ENABLED)
665 fprintf(output, "Object is a Location Set:\n");
666 xmlXPathDebugDumpLocationSet(output,
667 (xmlLocationSetPtr) cur->user, depth);
668#endif
669 break;
670 case XPATH_USERS:
671 fprintf(output, "Object is user defined\n");
672 break;
673 }
674}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000675
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000676static void
677xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000678 xmlXPathStepOpPtr op, int depth) {
679 int i;
680 char shift[100];
681
682 for (i = 0;((i < depth) && (i < 25));i++)
683 shift[2 * i] = shift[2 * i + 1] = ' ';
684 shift[2 * i] = shift[2 * i + 1] = 0;
685
686 fprintf(output, shift);
687 if (op == NULL) {
688 fprintf(output, "Step is NULL\n");
689 return;
690 }
691 switch (op->op) {
692 case XPATH_OP_END:
693 fprintf(output, "END"); break;
694 case XPATH_OP_AND:
695 fprintf(output, "AND"); break;
696 case XPATH_OP_OR:
697 fprintf(output, "OR"); break;
698 case XPATH_OP_EQUAL:
699 if (op->value)
700 fprintf(output, "EQUAL =");
701 else
702 fprintf(output, "EQUAL !=");
703 break;
704 case XPATH_OP_CMP:
705 if (op->value)
706 fprintf(output, "CMP <");
707 else
708 fprintf(output, "CMP >");
709 if (!op->value2)
710 fprintf(output, "=");
711 break;
712 case XPATH_OP_PLUS:
713 if (op->value == 0)
714 fprintf(output, "PLUS -");
715 else if (op->value == 1)
716 fprintf(output, "PLUS +");
717 else if (op->value == 2)
718 fprintf(output, "PLUS unary -");
719 else if (op->value == 3)
720 fprintf(output, "PLUS unary - -");
721 break;
722 case XPATH_OP_MULT:
723 if (op->value == 0)
724 fprintf(output, "MULT *");
725 else if (op->value == 1)
726 fprintf(output, "MULT div");
727 else
728 fprintf(output, "MULT mod");
729 break;
730 case XPATH_OP_UNION:
731 fprintf(output, "UNION"); break;
732 case XPATH_OP_ROOT:
733 fprintf(output, "ROOT"); break;
734 case XPATH_OP_NODE:
735 fprintf(output, "NODE"); break;
736 case XPATH_OP_RESET:
737 fprintf(output, "RESET"); break;
738 case XPATH_OP_SORT:
739 fprintf(output, "SORT"); break;
740 case XPATH_OP_COLLECT: {
741 xmlXPathAxisVal axis = op->value;
742 xmlXPathTestVal test = op->value2;
743 xmlXPathTypeVal type = op->value3;
744 const xmlChar *prefix = op->value4;
745 const xmlChar *name = op->value5;
746
747 fprintf(output, "COLLECT ");
748 switch (axis) {
749 case AXIS_ANCESTOR:
750 fprintf(output, " 'ancestors' "); break;
751 case AXIS_ANCESTOR_OR_SELF:
752 fprintf(output, " 'ancestors-or-self' "); break;
753 case AXIS_ATTRIBUTE:
754 fprintf(output, " 'attributes' "); break;
755 case AXIS_CHILD:
756 fprintf(output, " 'child' "); break;
757 case AXIS_DESCENDANT:
758 fprintf(output, " 'descendant' "); break;
759 case AXIS_DESCENDANT_OR_SELF:
760 fprintf(output, " 'descendant-or-self' "); break;
761 case AXIS_FOLLOWING:
762 fprintf(output, " 'following' "); break;
763 case AXIS_FOLLOWING_SIBLING:
764 fprintf(output, " 'following-siblings' "); break;
765 case AXIS_NAMESPACE:
766 fprintf(output, " 'namespace' "); break;
767 case AXIS_PARENT:
768 fprintf(output, " 'parent' "); break;
769 case AXIS_PRECEDING:
770 fprintf(output, " 'preceding' "); break;
771 case AXIS_PRECEDING_SIBLING:
772 fprintf(output, " 'preceding-sibling' "); break;
773 case AXIS_SELF:
774 fprintf(output, " 'self' "); break;
775 }
776 switch (test) {
777 case NODE_TEST_NONE:
778 fprintf(output, "'none' "); break;
779 case NODE_TEST_TYPE:
780 fprintf(output, "'type' "); break;
781 case NODE_TEST_PI:
782 fprintf(output, "'PI' "); break;
783 case NODE_TEST_ALL:
784 fprintf(output, "'all' "); break;
785 case NODE_TEST_NS:
786 fprintf(output, "'namespace' "); break;
787 case NODE_TEST_NAME:
788 fprintf(output, "'name' "); break;
789 }
790 switch (type) {
791 case NODE_TYPE_NODE:
792 fprintf(output, "'node' "); break;
793 case NODE_TYPE_COMMENT:
794 fprintf(output, "'comment' "); break;
795 case NODE_TYPE_TEXT:
796 fprintf(output, "'text' "); break;
797 case NODE_TYPE_PI:
798 fprintf(output, "'PI' "); break;
799 }
800 if (prefix != NULL)
801 fprintf(output, "%s:", prefix);
802 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +0000803 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000804 break;
805
806 }
807 case XPATH_OP_VALUE: {
808 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
809
810 fprintf(output, "ELEM ");
811 xmlXPathDebugDumpObject(output, object, 0);
812 goto finish;
813 }
814 case XPATH_OP_VARIABLE: {
815 const xmlChar *prefix = op->value5;
816 const xmlChar *name = op->value4;
817
818 if (prefix != NULL)
819 fprintf(output, "VARIABLE %s:%s", prefix, name);
820 else
821 fprintf(output, "VARIABLE %s", name);
822 break;
823 }
824 case XPATH_OP_FUNCTION: {
825 int nbargs = op->value;
826 const xmlChar *prefix = op->value5;
827 const xmlChar *name = op->value4;
828
829 if (prefix != NULL)
830 fprintf(output, "FUNCTION %s:%s(%d args)",
831 prefix, name, nbargs);
832 else
833 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
834 break;
835 }
836 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
837 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000838 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +0000839#ifdef LIBXML_XPTR_ENABLED
840 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
841#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000842 default:
843 fprintf(output, "UNKNOWN %d\n", op->op); return;
844 }
845 fprintf(output, "\n");
846finish:
847 if (op->ch1 >= 0)
848 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
849 if (op->ch2 >= 0)
850 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
851}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000852
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000853/**
854 * xmlXPathDebugDumpCompExpr:
855 * @output: the FILE * for the output
856 * @comp: the precompiled XPath expression
857 * @depth: the indentation level.
858 *
859 * Dumps the tree of the compiled XPath expression.
860 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000861void
862xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
863 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000864 int i;
865 char shift[100];
866
867 for (i = 0;((i < depth) && (i < 25));i++)
868 shift[2 * i] = shift[2 * i + 1] = ' ';
869 shift[2 * i] = shift[2 * i + 1] = 0;
870
871 fprintf(output, shift);
872
873 if (comp == NULL) {
874 fprintf(output, "Compiled Expression is NULL\n");
875 return;
876 }
877 fprintf(output, "Compiled Expression : %d elements\n",
878 comp->nbStep);
879 i = comp->last;
880 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
881}
Daniel Veillard017b1082001-06-21 11:20:21 +0000882#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000883
884/************************************************************************
885 * *
886 * Parser stacks related functions and macros *
887 * *
888 ************************************************************************/
889
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000890/**
891 * valuePop:
892 * @ctxt: an XPath evaluation context
893 *
894 * Pops the top XPath object from the value stack
895 *
896 * Returns the XPath object just removed
897 */
Daniel Veillard1c732d22002-11-30 11:22:59 +0000898extern xmlXPathObjectPtr
899valuePop(xmlXPathParserContextPtr ctxt)
900{
901 xmlXPathObjectPtr ret;
902
903 if (ctxt->valueNr <= 0)
904 return (0);
905 ctxt->valueNr--;
906 if (ctxt->valueNr > 0)
907 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
908 else
909 ctxt->value = NULL;
910 ret = ctxt->valueTab[ctxt->valueNr];
911 ctxt->valueTab[ctxt->valueNr] = 0;
912 return (ret);
913}
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000914/**
915 * valuePush:
916 * @ctxt: an XPath evaluation context
917 * @value: the XPath object
918 *
919 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000920 *
921 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000922 */
Daniel Veillard1c732d22002-11-30 11:22:59 +0000923extern int
924valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
925{
926 if (ctxt->valueNr >= ctxt->valueMax) {
927 ctxt->valueMax *= 2;
928 ctxt->valueTab =
929 (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
930 ctxt->valueMax *
931 sizeof(ctxt->valueTab[0]));
932 if (ctxt->valueTab == NULL) {
933 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
934 return (0);
935 }
936 }
937 ctxt->valueTab[ctxt->valueNr] = value;
938 ctxt->value = value;
939 return (ctxt->valueNr++);
940}
Owen Taylor3473f882001-02-23 17:55:21 +0000941
Thomas Broyerf06a3d82001-07-16 04:52:57 +0000942/**
943 * xmlXPathPopBoolean:
944 * @ctxt: an XPath parser context
945 *
946 * Pops a boolean from the stack, handling conversion if needed.
947 * Check error with #xmlXPathCheckError.
948 *
949 * Returns the boolean
950 */
951int
952xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
953 xmlXPathObjectPtr obj;
954 int ret;
955
956 obj = valuePop(ctxt);
957 if (obj == NULL) {
958 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
959 return(0);
960 }
961 ret = xmlXPathCastToBoolean(obj);
962 xmlXPathFreeObject(obj);
963 return(ret);
964}
965
966/**
967 * xmlXPathPopNumber:
968 * @ctxt: an XPath parser context
969 *
970 * Pops a number from the stack, handling conversion if needed.
971 * Check error with #xmlXPathCheckError.
972 *
973 * Returns the number
974 */
975double
976xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
977 xmlXPathObjectPtr obj;
978 double ret;
979
980 obj = valuePop(ctxt);
981 if (obj == NULL) {
982 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
983 return(0);
984 }
985 ret = xmlXPathCastToNumber(obj);
986 xmlXPathFreeObject(obj);
987 return(ret);
988}
989
990/**
991 * xmlXPathPopString:
992 * @ctxt: an XPath parser context
993 *
994 * Pops a string from the stack, handling conversion if needed.
995 * Check error with #xmlXPathCheckError.
996 *
997 * Returns the string
998 */
999xmlChar *
1000xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
1001 xmlXPathObjectPtr obj;
1002 xmlChar * ret;
1003
1004 obj = valuePop(ctxt);
1005 if (obj == NULL) {
1006 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1007 return(NULL);
1008 }
1009 ret = xmlXPathCastToString(obj);
1010 /* TODO: needs refactoring somewhere else */
1011 if (obj->stringval == ret)
1012 obj->stringval = NULL;
1013 xmlXPathFreeObject(obj);
1014 return(ret);
1015}
1016
1017/**
1018 * xmlXPathPopNodeSet:
1019 * @ctxt: an XPath parser context
1020 *
1021 * Pops a node-set from the stack, handling conversion if needed.
1022 * Check error with #xmlXPathCheckError.
1023 *
1024 * Returns the node-set
1025 */
1026xmlNodeSetPtr
1027xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
1028 xmlXPathObjectPtr obj;
1029 xmlNodeSetPtr ret;
1030
1031 if (ctxt->value == NULL) {
1032 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1033 return(NULL);
1034 }
1035 if (!xmlXPathStackIsNodeSet(ctxt)) {
1036 xmlXPathSetTypeError(ctxt);
1037 return(NULL);
1038 }
1039 obj = valuePop(ctxt);
1040 ret = obj->nodesetval;
1041 xmlXPathFreeNodeSetList(obj);
1042 return(ret);
1043}
1044
1045/**
1046 * xmlXPathPopExternal:
1047 * @ctxt: an XPath parser context
1048 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001049 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001050 * Check error with #xmlXPathCheckError.
1051 *
1052 * Returns the object
1053 */
1054void *
1055xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1056 xmlXPathObjectPtr obj;
1057 void * ret;
1058
1059 if (ctxt->value == NULL) {
1060 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1061 return(NULL);
1062 }
1063 if (ctxt->value->type != XPATH_USERS) {
1064 xmlXPathSetTypeError(ctxt);
1065 return(NULL);
1066 }
1067 obj = valuePop(ctxt);
1068 ret = obj->user;
1069 xmlXPathFreeObject(obj);
1070 return(ret);
1071}
1072
Owen Taylor3473f882001-02-23 17:55:21 +00001073/*
1074 * Macros for accessing the content. Those should be used only by the parser,
1075 * and not exported.
1076 *
1077 * Dirty macros, i.e. one need to make assumption on the context to use them
1078 *
1079 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1080 * CUR returns the current xmlChar value, i.e. a 8 bit value
1081 * in ISO-Latin or UTF-8.
1082 * This should be used internally by the parser
1083 * only to compare to ASCII values otherwise it would break when
1084 * running with UTF-8 encoding.
1085 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1086 * to compare on ASCII based substring.
1087 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1088 * strings within the parser.
1089 * CURRENT Returns the current char value, with the full decoding of
1090 * UTF-8 if we are using this mode. It returns an int.
1091 * NEXT Skip to the next character, this does the proper decoding
1092 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1093 * It returns the pointer to the current xmlChar.
1094 */
1095
1096#define CUR (*ctxt->cur)
1097#define SKIP(val) ctxt->cur += (val)
1098#define NXT(val) ctxt->cur[(val)]
1099#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001100#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1101
1102#define COPY_BUF(l,b,i,v) \
1103 if (l == 1) b[i++] = (xmlChar) v; \
1104 else i += xmlCopyChar(l,&b[i],v)
1105
1106#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001107
1108#define SKIP_BLANKS \
1109 while (IS_BLANK(*(ctxt->cur))) NEXT
1110
1111#define CURRENT (*ctxt->cur)
1112#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1113
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001114
1115#ifndef DBL_DIG
1116#define DBL_DIG 16
1117#endif
1118#ifndef DBL_EPSILON
1119#define DBL_EPSILON 1E-9
1120#endif
1121
1122#define UPPER_DOUBLE 1E9
1123#define LOWER_DOUBLE 1E-5
1124
1125#define INTEGER_DIGITS DBL_DIG
1126#define FRACTION_DIGITS (DBL_DIG + 1)
1127#define EXPONENT_DIGITS (3 + 2)
1128
1129/**
1130 * xmlXPathFormatNumber:
1131 * @number: number to format
1132 * @buffer: output buffer
1133 * @buffersize: size of output buffer
1134 *
1135 * Convert the number into a string representation.
1136 */
1137static void
1138xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1139{
Daniel Veillardcda96922001-08-21 10:56:31 +00001140 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001141 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001142 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001143 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001144 break;
1145 case -1:
1146 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001147 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001148 break;
1149 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001150 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001151 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001152 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001153 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001154 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001155 } else if (number == ((int) number)) {
1156 char work[30];
1157 char *ptr, *cur;
1158 int res, value = (int) number;
1159
1160 ptr = &buffer[0];
1161 if (value < 0) {
1162 *ptr++ = '-';
1163 value = -value;
1164 }
1165 if (value == 0) {
1166 *ptr++ = '0';
1167 } else {
1168 cur = &work[0];
1169 while (value != 0) {
1170 res = value % 10;
1171 value = value / 10;
1172 *cur++ = '0' + res;
1173 }
1174 cur--;
1175 while ((cur >= &work[0]) && (ptr - buffer < buffersize)) {
1176 *ptr++ = *cur--;
1177 }
1178 }
1179 if (ptr - buffer < buffersize) {
1180 *ptr = 0;
1181 } else if (buffersize > 0) {
1182 ptr--;
1183 *ptr = 0;
1184 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001185 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001186 /* 3 is sign, decimal point, and terminating zero */
1187 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1188 int integer_place, fraction_place;
1189 char *ptr;
1190 char *after_fraction;
1191 double absolute_value;
1192 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001193
Bjorn Reese70a9da52001-04-21 16:57:29 +00001194 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001195
Bjorn Reese70a9da52001-04-21 16:57:29 +00001196 /*
1197 * First choose format - scientific or regular floating point.
1198 * In either case, result is in work, and after_fraction points
1199 * just past the fractional part.
1200 */
1201 if ( ((absolute_value > UPPER_DOUBLE) ||
1202 (absolute_value < LOWER_DOUBLE)) &&
1203 (absolute_value != 0.0) ) {
1204 /* Use scientific notation */
1205 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1206 fraction_place = DBL_DIG - 1;
1207 snprintf(work, sizeof(work),"%*.*e",
1208 integer_place, fraction_place, number);
1209 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001210 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001211 else {
1212 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001213 if (absolute_value > 0.0)
1214 integer_place = 1 + (int)log10(absolute_value);
1215 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001216 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001217 fraction_place = (integer_place > 0)
1218 ? DBL_DIG - integer_place
1219 : DBL_DIG;
1220 size = snprintf(work, sizeof(work), "%0.*f",
1221 fraction_place, number);
1222 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001223 }
1224
Bjorn Reese70a9da52001-04-21 16:57:29 +00001225 /* Remove fractional trailing zeroes */
1226 ptr = after_fraction;
1227 while (*(--ptr) == '0')
1228 ;
1229 if (*ptr != '.')
1230 ptr++;
1231 strcpy(ptr, after_fraction);
1232
1233 /* Finally copy result back to caller */
1234 size = strlen(work) + 1;
1235 if (size > buffersize) {
1236 work[buffersize - 1] = 0;
1237 size = buffersize;
1238 }
1239 memcpy(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001240 }
1241 break;
1242 }
1243}
1244
Owen Taylor3473f882001-02-23 17:55:21 +00001245/************************************************************************
1246 * *
1247 * Error handling routines *
1248 * *
1249 ************************************************************************/
1250
1251
Daniel Veillardb44025c2001-10-11 22:55:55 +00001252static const char *xmlXPathErrorMessages[] = {
Owen Taylor3473f882001-02-23 17:55:21 +00001253 "Ok",
1254 "Number encoding",
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001255 "Unfinished literal",
1256 "Start of literal",
Owen Taylor3473f882001-02-23 17:55:21 +00001257 "Expected $ for variable reference",
1258 "Undefined variable",
1259 "Invalid predicate",
1260 "Invalid expression",
1261 "Missing closing curly brace",
1262 "Unregistered function",
1263 "Invalid operand",
1264 "Invalid type",
1265 "Invalid number of arguments",
1266 "Invalid context size",
1267 "Invalid context position",
1268 "Memory allocation error",
1269 "Syntax error",
1270 "Resource error",
1271 "Sub resource error",
Daniel Veillard61d80a22001-04-27 17:13:01 +00001272 "Undefined namespace prefix",
1273 "Encoding error",
1274 "Char out of XML range"
Owen Taylor3473f882001-02-23 17:55:21 +00001275};
1276
1277/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001278 * xmlXPatherror:
Owen Taylor3473f882001-02-23 17:55:21 +00001279 * @ctxt: the XPath Parser context
1280 * @file: the file name
1281 * @line: the line number
1282 * @no: the error number
1283 *
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001284 * Formats an error message.
Owen Taylor3473f882001-02-23 17:55:21 +00001285 */
1286void
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00001287xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
1288 int line ATTRIBUTE_UNUSED, int no) {
Owen Taylor3473f882001-02-23 17:55:21 +00001289 int n;
1290 const xmlChar *cur;
1291 const xmlChar *base;
1292
Owen Taylor3473f882001-02-23 17:55:21 +00001293 cur = ctxt->cur;
1294 base = ctxt->base;
Daniel Veillard118aed72002-09-24 14:13:13 +00001295 if ((cur == NULL) || (base == NULL)) {
1296 if ((ctxt->comp != NULL) && (ctxt->comp->expr != NULL)) {
1297 xmlGenericError(xmlGenericErrorContext,
1298 "XPath error %s in %s\n", xmlXPathErrorMessages[no],
1299 ctxt->comp->expr);
1300 } else {
1301 xmlGenericError(xmlGenericErrorContext,
1302 "XPath error %s\n", xmlXPathErrorMessages[no]);
1303 }
1304
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001305 return;
Daniel Veillard118aed72002-09-24 14:13:13 +00001306 }
1307 xmlGenericError(xmlGenericErrorContext,
1308 "XPath error %s\n", xmlXPathErrorMessages[no]);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001309
Owen Taylor3473f882001-02-23 17:55:21 +00001310 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
1311 cur--;
1312 }
1313 n = 0;
1314 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
1315 cur--;
1316 if ((*cur == '\n') || (*cur == '\r')) cur++;
1317 base = cur;
1318 n = 0;
1319 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
1320 xmlGenericError(xmlGenericErrorContext, "%c", (unsigned char) *cur++);
1321 n++;
1322 }
1323 xmlGenericError(xmlGenericErrorContext, "\n");
1324 cur = ctxt->cur;
1325 while ((*cur == '\n') || (*cur == '\r'))
1326 cur--;
1327 n = 0;
1328 while ((cur != base) && (n++ < 80)) {
1329 xmlGenericError(xmlGenericErrorContext, " ");
1330 base++;
1331 }
1332 xmlGenericError(xmlGenericErrorContext,"^\n");
1333}
1334
1335
1336/************************************************************************
1337 * *
1338 * Routines to handle NodeSets *
1339 * *
1340 ************************************************************************/
1341
1342/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001343 * xmlXPathOrderDocElems:
1344 * @doc: an input document
1345 *
1346 * Call this routine to speed up XPath computation on static documents.
1347 * This stamps all the element nodes with the document order
1348 * Like for line information, the order is kept in the element->content
1349 * field, the value stored is actually - the node number (startting at -1)
1350 * to be able to differenciate from line numbers.
1351 *
1352 * Returns the number of element found in the document or -1 in case
1353 * of error.
1354 */
1355long
1356xmlXPathOrderDocElems(xmlDocPtr doc) {
1357 long count = 0;
1358 xmlNodePtr cur;
1359
1360 if (doc == NULL)
1361 return(-1);
1362 cur = doc->children;
1363 while (cur != NULL) {
1364 if (cur->type == XML_ELEMENT_NODE) {
1365 cur->content = (void *) (-(++count));
1366 if (cur->children != NULL) {
1367 cur = cur->children;
1368 continue;
1369 }
1370 }
1371 if (cur->next != NULL) {
1372 cur = cur->next;
1373 continue;
1374 }
1375 do {
1376 cur = cur->parent;
1377 if (cur == NULL)
1378 break;
1379 if (cur == (xmlNodePtr) doc) {
1380 cur = NULL;
1381 break;
1382 }
1383 if (cur->next != NULL) {
1384 cur = cur->next;
1385 break;
1386 }
1387 } while (cur != NULL);
1388 }
1389 return(count);
1390}
1391
1392/**
Owen Taylor3473f882001-02-23 17:55:21 +00001393 * xmlXPathCmpNodes:
1394 * @node1: the first node
1395 * @node2: the second node
1396 *
1397 * Compare two nodes w.r.t document order
1398 *
1399 * Returns -2 in case of error 1 if first point < second point, 0 if
1400 * that's the same node, -1 otherwise
1401 */
1402int
1403xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1404 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001405 int attr1 = 0, attr2 = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001406 xmlNodePtr cur, root;
1407
1408 if ((node1 == NULL) || (node2 == NULL))
1409 return(-2);
1410 /*
1411 * a couple of optimizations which will avoid computations in most cases
1412 */
Daniel Veillardedfd5882003-03-07 14:20:40 +00001413 if (node1->type == XML_ATTRIBUTE_NODE) {
1414 attr1 = 1;
1415 node1 = node1->parent;
1416 }
1417 if (node2->type == XML_ATTRIBUTE_NODE) {
1418 attr2 = 1;
1419 node2 = node2->parent;
1420 }
1421 if (node1 == node2) {
1422 if (attr1 == attr2)
1423 return(0);
1424 if (attr2 == 1)
1425 return(1);
1426 return(-1);
1427 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00001428 if ((node1->type == XML_NAMESPACE_DECL) ||
1429 (node2->type == XML_NAMESPACE_DECL))
1430 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001431 if (node1 == node2->prev)
1432 return(1);
1433 if (node1 == node2->next)
1434 return(-1);
1435
1436 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001437 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001438 */
1439 if ((node1->type == XML_ELEMENT_NODE) &&
1440 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001441 (0 > (long) node1->content) &&
1442 (0 > (long) node2->content) &&
1443 (node1->doc == node2->doc)) {
1444 long l1, l2;
1445
1446 l1 = -((long) node1->content);
1447 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001448 if (l1 < l2)
1449 return(1);
1450 if (l1 > l2)
1451 return(-1);
1452 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001453
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001454 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001455 * compute depth to root
1456 */
1457 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1458 if (cur == node1)
1459 return(1);
1460 depth2++;
1461 }
1462 root = cur;
1463 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1464 if (cur == node2)
1465 return(-1);
1466 depth1++;
1467 }
1468 /*
1469 * Distinct document (or distinct entities :-( ) case.
1470 */
1471 if (root != cur) {
1472 return(-2);
1473 }
1474 /*
1475 * get the nearest common ancestor.
1476 */
1477 while (depth1 > depth2) {
1478 depth1--;
1479 node1 = node1->parent;
1480 }
1481 while (depth2 > depth1) {
1482 depth2--;
1483 node2 = node2->parent;
1484 }
1485 while (node1->parent != node2->parent) {
1486 node1 = node1->parent;
1487 node2 = node2->parent;
1488 /* should not happen but just in case ... */
1489 if ((node1 == NULL) || (node2 == NULL))
1490 return(-2);
1491 }
1492 /*
1493 * Find who's first.
1494 */
1495 if (node1 == node2->next)
1496 return(-1);
1497 for (cur = node1->next;cur != NULL;cur = cur->next)
1498 if (cur == node2)
1499 return(1);
1500 return(-1); /* assume there is no sibling list corruption */
1501}
1502
1503/**
1504 * xmlXPathNodeSetSort:
1505 * @set: the node set
1506 *
1507 * Sort the node set in document order
1508 */
1509void
1510xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001511 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001512 xmlNodePtr tmp;
1513
1514 if (set == NULL)
1515 return;
1516
1517 /* Use Shell's sort to sort the node-set */
1518 len = set->nodeNr;
1519 for (incr = len / 2; incr > 0; incr /= 2) {
1520 for (i = incr; i < len; i++) {
1521 j = i - incr;
1522 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001523 if (xmlXPathCmpNodes(set->nodeTab[j],
1524 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001525 tmp = set->nodeTab[j];
1526 set->nodeTab[j] = set->nodeTab[j + incr];
1527 set->nodeTab[j + incr] = tmp;
1528 j -= incr;
1529 } else
1530 break;
1531 }
1532 }
1533 }
1534}
1535
1536#define XML_NODESET_DEFAULT 10
1537/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001538 * xmlXPathNodeSetDupNs:
1539 * @node: the parent node of the namespace XPath node
1540 * @ns: the libxml namespace declaration node.
1541 *
1542 * Namespace node in libxml don't match the XPath semantic. In a node set
1543 * the namespace nodes are duplicated and the next pointer is set to the
1544 * parent node in the XPath semantic.
1545 *
1546 * Returns the newly created object.
1547 */
1548static xmlNodePtr
1549xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
1550 xmlNsPtr cur;
1551
1552 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1553 return(NULL);
1554 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
1555 return((xmlNodePtr) ns);
1556
1557 /*
1558 * Allocate a new Namespace and fill the fields.
1559 */
1560 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1561 if (cur == NULL) {
1562 xmlGenericError(xmlGenericErrorContext,
1563 "xmlXPathNodeSetDupNs : malloc failed\n");
1564 return(NULL);
1565 }
1566 memset(cur, 0, sizeof(xmlNs));
1567 cur->type = XML_NAMESPACE_DECL;
1568 if (ns->href != NULL)
1569 cur->href = xmlStrdup(ns->href);
1570 if (ns->prefix != NULL)
1571 cur->prefix = xmlStrdup(ns->prefix);
1572 cur->next = (xmlNsPtr) node;
1573 return((xmlNodePtr) cur);
1574}
1575
1576/**
1577 * xmlXPathNodeSetFreeNs:
1578 * @ns: the XPath namespace node found in a nodeset.
1579 *
1580 * Namespace node in libxml don't match the XPath semantic. In a node set
1581 * the namespace nodes are duplicated and the next pointer is set to the
1582 * parent node in the XPath semantic. Check if such a node need to be freed
1583 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001584void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001585xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
1586 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1587 return;
1588
1589 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
1590 if (ns->href != NULL)
1591 xmlFree((xmlChar *)ns->href);
1592 if (ns->prefix != NULL)
1593 xmlFree((xmlChar *)ns->prefix);
1594 xmlFree(ns);
1595 }
1596}
1597
1598/**
Owen Taylor3473f882001-02-23 17:55:21 +00001599 * xmlXPathNodeSetCreate:
1600 * @val: an initial xmlNodePtr, or NULL
1601 *
1602 * Create a new xmlNodeSetPtr of type double and of value @val
1603 *
1604 * Returns the newly created object.
1605 */
1606xmlNodeSetPtr
1607xmlXPathNodeSetCreate(xmlNodePtr val) {
1608 xmlNodeSetPtr ret;
1609
1610 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1611 if (ret == NULL) {
1612 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001613 "xmlXPathNodeSetCreate: out of memory\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001614 return(NULL);
1615 }
1616 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1617 if (val != NULL) {
1618 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1619 sizeof(xmlNodePtr));
1620 if (ret->nodeTab == NULL) {
1621 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001622 "xmlXPathNodeSetCreate: out of memory\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001623 return(NULL);
1624 }
1625 memset(ret->nodeTab, 0 ,
1626 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1627 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001628 if (val->type == XML_NAMESPACE_DECL) {
1629 xmlNsPtr ns = (xmlNsPtr) val;
1630
1631 ret->nodeTab[ret->nodeNr++] =
1632 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1633 } else
1634 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001635 }
1636 return(ret);
1637}
1638
1639/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001640 * xmlXPathNodeSetContains:
1641 * @cur: the node-set
1642 * @val: the node
1643 *
1644 * checks whether @cur contains @val
1645 *
1646 * Returns true (1) if @cur contains @val, false (0) otherwise
1647 */
1648int
1649xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1650 int i;
1651
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001652 if (val->type == XML_NAMESPACE_DECL) {
1653 for (i = 0; i < cur->nodeNr; i++) {
1654 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1655 xmlNsPtr ns1, ns2;
1656
1657 ns1 = (xmlNsPtr) val;
1658 ns2 = (xmlNsPtr) cur->nodeTab[i];
1659 if (ns1 == ns2)
1660 return(1);
1661 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
1662 (xmlStrEqual(ns1->prefix, ns2->prefix)))
1663 return(1);
1664 }
1665 }
1666 } else {
1667 for (i = 0; i < cur->nodeNr; i++) {
1668 if (cur->nodeTab[i] == val)
1669 return(1);
1670 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001671 }
1672 return(0);
1673}
1674
1675/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001676 * xmlXPathNodeSetAddNs:
1677 * @cur: the initial node set
1678 * @node: the hosting node
1679 * @ns: a the namespace node
1680 *
1681 * add a new namespace node to an existing NodeSet
1682 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00001683void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001684xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
1685 int i;
1686
1687 if ((ns == NULL) || (node == NULL) || (ns->type != XML_NAMESPACE_DECL) ||
1688 (node->type != XML_ELEMENT_NODE))
1689 return;
1690
1691 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1692 /*
1693 * check against doublons
1694 */
1695 for (i = 0;i < cur->nodeNr;i++) {
1696 if ((cur->nodeTab[i] != NULL) &&
1697 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00001698 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001699 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
1700 return;
1701 }
1702
1703 /*
1704 * grow the nodeTab if needed
1705 */
1706 if (cur->nodeMax == 0) {
1707 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1708 sizeof(xmlNodePtr));
1709 if (cur->nodeTab == NULL) {
1710 xmlGenericError(xmlGenericErrorContext,
1711 "xmlXPathNodeSetAdd: out of memory\n");
1712 return;
1713 }
1714 memset(cur->nodeTab, 0 ,
1715 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1716 cur->nodeMax = XML_NODESET_DEFAULT;
1717 } else if (cur->nodeNr == cur->nodeMax) {
1718 xmlNodePtr *temp;
1719
1720 cur->nodeMax *= 2;
1721 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1722 sizeof(xmlNodePtr));
1723 if (temp == NULL) {
1724 xmlGenericError(xmlGenericErrorContext,
1725 "xmlXPathNodeSetAdd: out of memory\n");
1726 return;
1727 }
1728 cur->nodeTab = temp;
1729 }
1730 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
1731}
1732
1733/**
Owen Taylor3473f882001-02-23 17:55:21 +00001734 * xmlXPathNodeSetAdd:
1735 * @cur: the initial node set
1736 * @val: a new xmlNodePtr
1737 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001738 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00001739 */
1740void
1741xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1742 int i;
1743
1744 if (val == NULL) return;
1745
Daniel Veillardef0b4502003-03-24 13:57:34 +00001746#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001747 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1748 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001749#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001750
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001751 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001752 /*
1753 * check against doublons
1754 */
1755 for (i = 0;i < cur->nodeNr;i++)
1756 if (cur->nodeTab[i] == val) return;
1757
1758 /*
1759 * grow the nodeTab if needed
1760 */
1761 if (cur->nodeMax == 0) {
1762 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1763 sizeof(xmlNodePtr));
1764 if (cur->nodeTab == NULL) {
1765 xmlGenericError(xmlGenericErrorContext,
1766 "xmlXPathNodeSetAdd: out of memory\n");
1767 return;
1768 }
1769 memset(cur->nodeTab, 0 ,
1770 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1771 cur->nodeMax = XML_NODESET_DEFAULT;
1772 } else if (cur->nodeNr == cur->nodeMax) {
1773 xmlNodePtr *temp;
1774
1775 cur->nodeMax *= 2;
1776 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1777 sizeof(xmlNodePtr));
1778 if (temp == NULL) {
1779 xmlGenericError(xmlGenericErrorContext,
1780 "xmlXPathNodeSetAdd: out of memory\n");
1781 return;
1782 }
1783 cur->nodeTab = temp;
1784 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001785 if (val->type == XML_NAMESPACE_DECL) {
1786 xmlNsPtr ns = (xmlNsPtr) val;
1787
1788 cur->nodeTab[cur->nodeNr++] =
1789 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1790 } else
1791 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001792}
1793
1794/**
1795 * xmlXPathNodeSetAddUnique:
1796 * @cur: the initial node set
1797 * @val: a new xmlNodePtr
1798 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001799 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00001800 * when we are sure the node is not already in the set.
1801 */
1802void
1803xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1804 if (val == NULL) return;
1805
Daniel Veillardef0b4502003-03-24 13:57:34 +00001806#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001807 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1808 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001809#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001810
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001811 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001812 /*
1813 * grow the nodeTab if needed
1814 */
1815 if (cur->nodeMax == 0) {
1816 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1817 sizeof(xmlNodePtr));
1818 if (cur->nodeTab == NULL) {
1819 xmlGenericError(xmlGenericErrorContext,
1820 "xmlXPathNodeSetAddUnique: out of memory\n");
1821 return;
1822 }
1823 memset(cur->nodeTab, 0 ,
1824 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1825 cur->nodeMax = XML_NODESET_DEFAULT;
1826 } else if (cur->nodeNr == cur->nodeMax) {
1827 xmlNodePtr *temp;
1828
1829 cur->nodeMax *= 2;
1830 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1831 sizeof(xmlNodePtr));
1832 if (temp == NULL) {
1833 xmlGenericError(xmlGenericErrorContext,
1834 "xmlXPathNodeSetAddUnique: out of memory\n");
1835 return;
1836 }
1837 cur->nodeTab = temp;
1838 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001839 if (val->type == XML_NAMESPACE_DECL) {
1840 xmlNsPtr ns = (xmlNsPtr) val;
1841
1842 cur->nodeTab[cur->nodeNr++] =
1843 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1844 } else
1845 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001846}
1847
1848/**
1849 * xmlXPathNodeSetMerge:
1850 * @val1: the first NodeSet or NULL
1851 * @val2: the second NodeSet
1852 *
1853 * Merges two nodesets, all nodes from @val2 are added to @val1
1854 * if @val1 is NULL, a new set is created and copied from @val2
1855 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001856 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00001857 */
1858xmlNodeSetPtr
1859xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001860 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001861
1862 if (val2 == NULL) return(val1);
1863 if (val1 == NULL) {
1864 val1 = xmlXPathNodeSetCreate(NULL);
1865 }
1866
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001867 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001868 initNr = val1->nodeNr;
1869
1870 for (i = 0;i < val2->nodeNr;i++) {
1871 /*
1872 * check against doublons
1873 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001874 skip = 0;
1875 for (j = 0; j < initNr; j++) {
1876 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1877 skip = 1;
1878 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001879 } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) &&
1880 (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) {
1881 xmlNsPtr ns1, ns2;
1882 ns1 = (xmlNsPtr) val1->nodeTab[j];
1883 ns2 = (xmlNsPtr) val2->nodeTab[i];
1884 if ((ns1->next == ns2->next) &&
1885 (xmlStrEqual(ns1->prefix, ns2->prefix))) {
1886 skip = 1;
1887 break;
1888 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001889 }
1890 }
1891 if (skip)
1892 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00001893
1894 /*
1895 * grow the nodeTab if needed
1896 */
1897 if (val1->nodeMax == 0) {
1898 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1899 sizeof(xmlNodePtr));
1900 if (val1->nodeTab == NULL) {
1901 xmlGenericError(xmlGenericErrorContext,
1902 "xmlXPathNodeSetMerge: out of memory\n");
1903 return(NULL);
1904 }
1905 memset(val1->nodeTab, 0 ,
1906 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1907 val1->nodeMax = XML_NODESET_DEFAULT;
1908 } else if (val1->nodeNr == val1->nodeMax) {
1909 xmlNodePtr *temp;
1910
1911 val1->nodeMax *= 2;
1912 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1913 sizeof(xmlNodePtr));
1914 if (temp == NULL) {
1915 xmlGenericError(xmlGenericErrorContext,
1916 "xmlXPathNodeSetMerge: out of memory\n");
1917 return(NULL);
1918 }
1919 val1->nodeTab = temp;
1920 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001921 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1922 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1923
1924 val1->nodeTab[val1->nodeNr++] =
1925 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1926 } else
1927 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00001928 }
1929
1930 return(val1);
1931}
1932
1933/**
Daniel Veillard75be0132002-03-13 10:03:35 +00001934 * xmlXPathNodeSetMergeUnique:
1935 * @val1: the first NodeSet or NULL
1936 * @val2: the second NodeSet
1937 *
1938 * Merges two nodesets, all nodes from @val2 are added to @val1
1939 * if @val1 is NULL, a new set is created and copied from @val2
1940 *
1941 * Returns @val1 once extended or NULL in case of error.
1942 */
1943static xmlNodeSetPtr
1944xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
1945 int i, initNr;
1946
1947 if (val2 == NULL) return(val1);
1948 if (val1 == NULL) {
1949 val1 = xmlXPathNodeSetCreate(NULL);
1950 }
1951
1952 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1953 initNr = val1->nodeNr;
1954
1955 for (i = 0;i < val2->nodeNr;i++) {
1956 /*
1957 * grow the nodeTab if needed
1958 */
1959 if (val1->nodeMax == 0) {
1960 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1961 sizeof(xmlNodePtr));
1962 if (val1->nodeTab == NULL) {
1963 xmlGenericError(xmlGenericErrorContext,
1964 "xmlXPathNodeSetMerge: out of memory\n");
1965 return(NULL);
1966 }
1967 memset(val1->nodeTab, 0 ,
1968 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1969 val1->nodeMax = XML_NODESET_DEFAULT;
1970 } else if (val1->nodeNr == val1->nodeMax) {
1971 xmlNodePtr *temp;
1972
1973 val1->nodeMax *= 2;
1974 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1975 sizeof(xmlNodePtr));
1976 if (temp == NULL) {
1977 xmlGenericError(xmlGenericErrorContext,
1978 "xmlXPathNodeSetMerge: out of memory\n");
1979 return(NULL);
1980 }
1981 val1->nodeTab = temp;
1982 }
1983 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1984 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1985
1986 val1->nodeTab[val1->nodeNr++] =
1987 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1988 } else
1989 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
1990 }
1991
1992 return(val1);
1993}
1994
1995/**
Owen Taylor3473f882001-02-23 17:55:21 +00001996 * xmlXPathNodeSetDel:
1997 * @cur: the initial node set
1998 * @val: an xmlNodePtr
1999 *
2000 * Removes an xmlNodePtr from an existing NodeSet
2001 */
2002void
2003xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
2004 int i;
2005
2006 if (cur == NULL) return;
2007 if (val == NULL) return;
2008
2009 /*
2010 * check against doublons
2011 */
2012 for (i = 0;i < cur->nodeNr;i++)
2013 if (cur->nodeTab[i] == val) break;
2014
2015 if (i >= cur->nodeNr) {
2016#ifdef DEBUG
2017 xmlGenericError(xmlGenericErrorContext,
2018 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
2019 val->name);
2020#endif
2021 return;
2022 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002023 if ((cur->nodeTab[i] != NULL) &&
2024 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
2025 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002026 cur->nodeNr--;
2027 for (;i < cur->nodeNr;i++)
2028 cur->nodeTab[i] = cur->nodeTab[i + 1];
2029 cur->nodeTab[cur->nodeNr] = NULL;
2030}
2031
2032/**
2033 * xmlXPathNodeSetRemove:
2034 * @cur: the initial node set
2035 * @val: the index to remove
2036 *
2037 * Removes an entry from an existing NodeSet list.
2038 */
2039void
2040xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
2041 if (cur == NULL) return;
2042 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002043 if ((cur->nodeTab[val] != NULL) &&
2044 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
2045 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00002046 cur->nodeNr--;
2047 for (;val < cur->nodeNr;val++)
2048 cur->nodeTab[val] = cur->nodeTab[val + 1];
2049 cur->nodeTab[cur->nodeNr] = NULL;
2050}
2051
2052/**
2053 * xmlXPathFreeNodeSet:
2054 * @obj: the xmlNodeSetPtr to free
2055 *
2056 * Free the NodeSet compound (not the actual nodes !).
2057 */
2058void
2059xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
2060 if (obj == NULL) return;
2061 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002062 int i;
2063
2064 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
2065 for (i = 0;i < obj->nodeNr;i++)
2066 if ((obj->nodeTab[i] != NULL) &&
2067 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
2068 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002069 xmlFree(obj->nodeTab);
2070 }
Owen Taylor3473f882001-02-23 17:55:21 +00002071 xmlFree(obj);
2072}
2073
2074/**
2075 * xmlXPathFreeValueTree:
2076 * @obj: the xmlNodeSetPtr to free
2077 *
2078 * Free the NodeSet compound and the actual tree, this is different
2079 * from xmlXPathFreeNodeSet()
2080 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002081static void
Owen Taylor3473f882001-02-23 17:55:21 +00002082xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
2083 int i;
2084
2085 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002086
2087 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002088 for (i = 0;i < obj->nodeNr;i++) {
2089 if (obj->nodeTab[i] != NULL) {
2090 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2091 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
2092 } else {
2093 xmlFreeNodeList(obj->nodeTab[i]);
2094 }
2095 }
2096 }
Owen Taylor3473f882001-02-23 17:55:21 +00002097 xmlFree(obj->nodeTab);
2098 }
Owen Taylor3473f882001-02-23 17:55:21 +00002099 xmlFree(obj);
2100}
2101
2102#if defined(DEBUG) || defined(DEBUG_STEP)
2103/**
2104 * xmlGenericErrorContextNodeSet:
2105 * @output: a FILE * for the output
2106 * @obj: the xmlNodeSetPtr to free
2107 *
2108 * Quick display of a NodeSet
2109 */
2110void
2111xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
2112 int i;
2113
2114 if (output == NULL) output = xmlGenericErrorContext;
2115 if (obj == NULL) {
2116 fprintf(output, "NodeSet == NULL !\n");
2117 return;
2118 }
2119 if (obj->nodeNr == 0) {
2120 fprintf(output, "NodeSet is empty\n");
2121 return;
2122 }
2123 if (obj->nodeTab == NULL) {
2124 fprintf(output, " nodeTab == NULL !\n");
2125 return;
2126 }
2127 for (i = 0; i < obj->nodeNr; i++) {
2128 if (obj->nodeTab[i] == NULL) {
2129 fprintf(output, " NULL !\n");
2130 return;
2131 }
2132 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
2133 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
2134 fprintf(output, " /");
2135 else if (obj->nodeTab[i]->name == NULL)
2136 fprintf(output, " noname!");
2137 else fprintf(output, " %s", obj->nodeTab[i]->name);
2138 }
2139 fprintf(output, "\n");
2140}
2141#endif
2142
2143/**
2144 * xmlXPathNewNodeSet:
2145 * @val: the NodePtr value
2146 *
2147 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2148 * it with the single Node @val
2149 *
2150 * Returns the newly created object.
2151 */
2152xmlXPathObjectPtr
2153xmlXPathNewNodeSet(xmlNodePtr val) {
2154 xmlXPathObjectPtr ret;
2155
2156 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2157 if (ret == NULL) {
2158 xmlGenericError(xmlGenericErrorContext,
2159 "xmlXPathNewNodeSet: out of memory\n");
2160 return(NULL);
2161 }
2162 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2163 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00002164 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002165 ret->nodesetval = xmlXPathNodeSetCreate(val);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002166 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002167 return(ret);
2168}
2169
2170/**
2171 * xmlXPathNewValueTree:
2172 * @val: the NodePtr value
2173 *
2174 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
2175 * it with the tree root @val
2176 *
2177 * Returns the newly created object.
2178 */
2179xmlXPathObjectPtr
2180xmlXPathNewValueTree(xmlNodePtr val) {
2181 xmlXPathObjectPtr ret;
2182
2183 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2184 if (ret == NULL) {
2185 xmlGenericError(xmlGenericErrorContext,
2186 "xmlXPathNewNodeSet: out of memory\n");
2187 return(NULL);
2188 }
2189 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2190 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002191 ret->boolval = 1;
2192 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00002193 ret->nodesetval = xmlXPathNodeSetCreate(val);
2194 return(ret);
2195}
2196
2197/**
2198 * xmlXPathNewNodeSetList:
2199 * @val: an existing NodeSet
2200 *
2201 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2202 * it with the Nodeset @val
2203 *
2204 * Returns the newly created object.
2205 */
2206xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002207xmlXPathNewNodeSetList(xmlNodeSetPtr val)
2208{
Owen Taylor3473f882001-02-23 17:55:21 +00002209 xmlXPathObjectPtr ret;
2210 int i;
2211
2212 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002213 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002214 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002215 ret = xmlXPathNewNodeSet(NULL);
2216 else {
2217 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
2218 for (i = 1; i < val->nodeNr; ++i)
2219 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2220 }
Owen Taylor3473f882001-02-23 17:55:21 +00002221
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002222 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002223}
2224
2225/**
2226 * xmlXPathWrapNodeSet:
2227 * @val: the NodePtr value
2228 *
2229 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2230 *
2231 * Returns the newly created object.
2232 */
2233xmlXPathObjectPtr
2234xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2235 xmlXPathObjectPtr ret;
2236
2237 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2238 if (ret == NULL) {
2239 xmlGenericError(xmlGenericErrorContext,
2240 "xmlXPathWrapNodeSet: out of memory\n");
2241 return(NULL);
2242 }
2243 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2244 ret->type = XPATH_NODESET;
2245 ret->nodesetval = val;
2246 return(ret);
2247}
2248
2249/**
2250 * xmlXPathFreeNodeSetList:
2251 * @obj: an existing NodeSetList object
2252 *
2253 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2254 * the list contrary to xmlXPathFreeObject().
2255 */
2256void
2257xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2258 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002259 xmlFree(obj);
2260}
2261
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002262/**
2263 * xmlXPathDifference:
2264 * @nodes1: a node-set
2265 * @nodes2: a node-set
2266 *
2267 * Implements the EXSLT - Sets difference() function:
2268 * node-set set:difference (node-set, node-set)
2269 *
2270 * Returns the difference between the two node sets, or nodes1 if
2271 * nodes2 is empty
2272 */
2273xmlNodeSetPtr
2274xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2275 xmlNodeSetPtr ret;
2276 int i, l1;
2277 xmlNodePtr cur;
2278
2279 if (xmlXPathNodeSetIsEmpty(nodes2))
2280 return(nodes1);
2281
2282 ret = xmlXPathNodeSetCreate(NULL);
2283 if (xmlXPathNodeSetIsEmpty(nodes1))
2284 return(ret);
2285
2286 l1 = xmlXPathNodeSetGetLength(nodes1);
2287
2288 for (i = 0; i < l1; i++) {
2289 cur = xmlXPathNodeSetItem(nodes1, i);
2290 if (!xmlXPathNodeSetContains(nodes2, cur))
2291 xmlXPathNodeSetAddUnique(ret, cur);
2292 }
2293 return(ret);
2294}
2295
2296/**
2297 * xmlXPathIntersection:
2298 * @nodes1: a node-set
2299 * @nodes2: a node-set
2300 *
2301 * Implements the EXSLT - Sets intersection() function:
2302 * node-set set:intersection (node-set, node-set)
2303 *
2304 * Returns a node set comprising the nodes that are within both the
2305 * node sets passed as arguments
2306 */
2307xmlNodeSetPtr
2308xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2309 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2310 int i, l1;
2311 xmlNodePtr cur;
2312
2313 if (xmlXPathNodeSetIsEmpty(nodes1))
2314 return(ret);
2315 if (xmlXPathNodeSetIsEmpty(nodes2))
2316 return(ret);
2317
2318 l1 = xmlXPathNodeSetGetLength(nodes1);
2319
2320 for (i = 0; i < l1; i++) {
2321 cur = xmlXPathNodeSetItem(nodes1, i);
2322 if (xmlXPathNodeSetContains(nodes2, cur))
2323 xmlXPathNodeSetAddUnique(ret, cur);
2324 }
2325 return(ret);
2326}
2327
2328/**
2329 * xmlXPathDistinctSorted:
2330 * @nodes: a node-set, sorted by document order
2331 *
2332 * Implements the EXSLT - Sets distinct() function:
2333 * node-set set:distinct (node-set)
2334 *
2335 * Returns a subset of the nodes contained in @nodes, or @nodes if
2336 * it is empty
2337 */
2338xmlNodeSetPtr
2339xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2340 xmlNodeSetPtr ret;
2341 xmlHashTablePtr hash;
2342 int i, l;
2343 xmlChar * strval;
2344 xmlNodePtr cur;
2345
2346 if (xmlXPathNodeSetIsEmpty(nodes))
2347 return(nodes);
2348
2349 ret = xmlXPathNodeSetCreate(NULL);
2350 l = xmlXPathNodeSetGetLength(nodes);
2351 hash = xmlHashCreate (l);
2352 for (i = 0; i < l; i++) {
2353 cur = xmlXPathNodeSetItem(nodes, i);
2354 strval = xmlXPathCastNodeToString(cur);
2355 if (xmlHashLookup(hash, strval) == NULL) {
2356 xmlHashAddEntry(hash, strval, strval);
2357 xmlXPathNodeSetAddUnique(ret, cur);
2358 } else {
2359 xmlFree(strval);
2360 }
2361 }
2362 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2363 return(ret);
2364}
2365
2366/**
2367 * xmlXPathDistinct:
2368 * @nodes: a node-set
2369 *
2370 * Implements the EXSLT - Sets distinct() function:
2371 * node-set set:distinct (node-set)
2372 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2373 * is called with the sorted node-set
2374 *
2375 * Returns a subset of the nodes contained in @nodes, or @nodes if
2376 * it is empty
2377 */
2378xmlNodeSetPtr
2379xmlXPathDistinct (xmlNodeSetPtr nodes) {
2380 if (xmlXPathNodeSetIsEmpty(nodes))
2381 return(nodes);
2382
2383 xmlXPathNodeSetSort(nodes);
2384 return(xmlXPathDistinctSorted(nodes));
2385}
2386
2387/**
2388 * xmlXPathHasSameNodes:
2389 * @nodes1: a node-set
2390 * @nodes2: a node-set
2391 *
2392 * Implements the EXSLT - Sets has-same-nodes function:
2393 * boolean set:has-same-node(node-set, node-set)
2394 *
2395 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2396 * otherwise
2397 */
2398int
2399xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2400 int i, l;
2401 xmlNodePtr cur;
2402
2403 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2404 xmlXPathNodeSetIsEmpty(nodes2))
2405 return(0);
2406
2407 l = xmlXPathNodeSetGetLength(nodes1);
2408 for (i = 0; i < l; i++) {
2409 cur = xmlXPathNodeSetItem(nodes1, i);
2410 if (xmlXPathNodeSetContains(nodes2, cur))
2411 return(1);
2412 }
2413 return(0);
2414}
2415
2416/**
2417 * xmlXPathNodeLeadingSorted:
2418 * @nodes: a node-set, sorted by document order
2419 * @node: a node
2420 *
2421 * Implements the EXSLT - Sets leading() function:
2422 * node-set set:leading (node-set, node-set)
2423 *
2424 * Returns the nodes in @nodes that precede @node in document order,
2425 * @nodes if @node is NULL or an empty node-set if @nodes
2426 * doesn't contain @node
2427 */
2428xmlNodeSetPtr
2429xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2430 int i, l;
2431 xmlNodePtr cur;
2432 xmlNodeSetPtr ret;
2433
2434 if (node == NULL)
2435 return(nodes);
2436
2437 ret = xmlXPathNodeSetCreate(NULL);
2438 if (xmlXPathNodeSetIsEmpty(nodes) ||
2439 (!xmlXPathNodeSetContains(nodes, node)))
2440 return(ret);
2441
2442 l = xmlXPathNodeSetGetLength(nodes);
2443 for (i = 0; i < l; i++) {
2444 cur = xmlXPathNodeSetItem(nodes, i);
2445 if (cur == node)
2446 break;
2447 xmlXPathNodeSetAddUnique(ret, cur);
2448 }
2449 return(ret);
2450}
2451
2452/**
2453 * xmlXPathNodeLeading:
2454 * @nodes: a node-set
2455 * @node: a node
2456 *
2457 * Implements the EXSLT - Sets leading() function:
2458 * node-set set:leading (node-set, node-set)
2459 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2460 * is called.
2461 *
2462 * Returns the nodes in @nodes that precede @node in document order,
2463 * @nodes if @node is NULL or an empty node-set if @nodes
2464 * doesn't contain @node
2465 */
2466xmlNodeSetPtr
2467xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2468 xmlXPathNodeSetSort(nodes);
2469 return(xmlXPathNodeLeadingSorted(nodes, node));
2470}
2471
2472/**
2473 * xmlXPathLeadingSorted:
2474 * @nodes1: a node-set, sorted by document order
2475 * @nodes2: a node-set, sorted by document order
2476 *
2477 * Implements the EXSLT - Sets leading() function:
2478 * node-set set:leading (node-set, node-set)
2479 *
2480 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2481 * in document order, @nodes1 if @nodes2 is NULL or empty or
2482 * an empty node-set if @nodes1 doesn't contain @nodes2
2483 */
2484xmlNodeSetPtr
2485xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2486 if (xmlXPathNodeSetIsEmpty(nodes2))
2487 return(nodes1);
2488 return(xmlXPathNodeLeadingSorted(nodes1,
2489 xmlXPathNodeSetItem(nodes2, 1)));
2490}
2491
2492/**
2493 * xmlXPathLeading:
2494 * @nodes1: a node-set
2495 * @nodes2: a node-set
2496 *
2497 * Implements the EXSLT - Sets leading() function:
2498 * node-set set:leading (node-set, node-set)
2499 * @nodes1 and @nodes2 are sorted by document order, then
2500 * #exslSetsLeadingSorted is called.
2501 *
2502 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2503 * in document order, @nodes1 if @nodes2 is NULL or empty or
2504 * an empty node-set if @nodes1 doesn't contain @nodes2
2505 */
2506xmlNodeSetPtr
2507xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2508 if (xmlXPathNodeSetIsEmpty(nodes2))
2509 return(nodes1);
2510 if (xmlXPathNodeSetIsEmpty(nodes1))
2511 return(xmlXPathNodeSetCreate(NULL));
2512 xmlXPathNodeSetSort(nodes1);
2513 xmlXPathNodeSetSort(nodes2);
2514 return(xmlXPathNodeLeadingSorted(nodes1,
2515 xmlXPathNodeSetItem(nodes2, 1)));
2516}
2517
2518/**
2519 * xmlXPathNodeTrailingSorted:
2520 * @nodes: a node-set, sorted by document order
2521 * @node: a node
2522 *
2523 * Implements the EXSLT - Sets trailing() function:
2524 * node-set set:trailing (node-set, node-set)
2525 *
2526 * Returns the nodes in @nodes that follow @node in document order,
2527 * @nodes if @node is NULL or an empty node-set if @nodes
2528 * doesn't contain @node
2529 */
2530xmlNodeSetPtr
2531xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2532 int i, l;
2533 xmlNodePtr cur;
2534 xmlNodeSetPtr ret;
2535
2536 if (node == NULL)
2537 return(nodes);
2538
2539 ret = xmlXPathNodeSetCreate(NULL);
2540 if (xmlXPathNodeSetIsEmpty(nodes) ||
2541 (!xmlXPathNodeSetContains(nodes, node)))
2542 return(ret);
2543
2544 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002545 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002546 cur = xmlXPathNodeSetItem(nodes, i);
2547 if (cur == node)
2548 break;
2549 xmlXPathNodeSetAddUnique(ret, cur);
2550 }
2551 return(ret);
2552}
2553
2554/**
2555 * xmlXPathNodeTrailing:
2556 * @nodes: a node-set
2557 * @node: a node
2558 *
2559 * Implements the EXSLT - Sets trailing() function:
2560 * node-set set:trailing (node-set, node-set)
2561 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2562 * is called.
2563 *
2564 * Returns the nodes in @nodes that follow @node in document order,
2565 * @nodes if @node is NULL or an empty node-set if @nodes
2566 * doesn't contain @node
2567 */
2568xmlNodeSetPtr
2569xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2570 xmlXPathNodeSetSort(nodes);
2571 return(xmlXPathNodeTrailingSorted(nodes, node));
2572}
2573
2574/**
2575 * xmlXPathTrailingSorted:
2576 * @nodes1: a node-set, sorted by document order
2577 * @nodes2: a node-set, sorted by document order
2578 *
2579 * Implements the EXSLT - Sets trailing() function:
2580 * node-set set:trailing (node-set, node-set)
2581 *
2582 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2583 * in document order, @nodes1 if @nodes2 is NULL or empty or
2584 * an empty node-set if @nodes1 doesn't contain @nodes2
2585 */
2586xmlNodeSetPtr
2587xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2588 if (xmlXPathNodeSetIsEmpty(nodes2))
2589 return(nodes1);
2590 return(xmlXPathNodeTrailingSorted(nodes1,
2591 xmlXPathNodeSetItem(nodes2, 0)));
2592}
2593
2594/**
2595 * xmlXPathTrailing:
2596 * @nodes1: a node-set
2597 * @nodes2: a node-set
2598 *
2599 * Implements the EXSLT - Sets trailing() function:
2600 * node-set set:trailing (node-set, node-set)
2601 * @nodes1 and @nodes2 are sorted by document order, then
2602 * #xmlXPathTrailingSorted is called.
2603 *
2604 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2605 * in document order, @nodes1 if @nodes2 is NULL or empty or
2606 * an empty node-set if @nodes1 doesn't contain @nodes2
2607 */
2608xmlNodeSetPtr
2609xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2610 if (xmlXPathNodeSetIsEmpty(nodes2))
2611 return(nodes1);
2612 if (xmlXPathNodeSetIsEmpty(nodes1))
2613 return(xmlXPathNodeSetCreate(NULL));
2614 xmlXPathNodeSetSort(nodes1);
2615 xmlXPathNodeSetSort(nodes2);
2616 return(xmlXPathNodeTrailingSorted(nodes1,
2617 xmlXPathNodeSetItem(nodes2, 0)));
2618}
2619
Owen Taylor3473f882001-02-23 17:55:21 +00002620/************************************************************************
2621 * *
2622 * Routines to handle extra functions *
2623 * *
2624 ************************************************************************/
2625
2626/**
2627 * xmlXPathRegisterFunc:
2628 * @ctxt: the XPath context
2629 * @name: the function name
2630 * @f: the function implementation or NULL
2631 *
2632 * Register a new function. If @f is NULL it unregisters the function
2633 *
2634 * Returns 0 in case of success, -1 in case of error
2635 */
2636int
2637xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2638 xmlXPathFunction f) {
2639 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2640}
2641
2642/**
2643 * xmlXPathRegisterFuncNS:
2644 * @ctxt: the XPath context
2645 * @name: the function name
2646 * @ns_uri: the function namespace URI
2647 * @f: the function implementation or NULL
2648 *
2649 * Register a new function. If @f is NULL it unregisters the function
2650 *
2651 * Returns 0 in case of success, -1 in case of error
2652 */
2653int
2654xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2655 const xmlChar *ns_uri, xmlXPathFunction f) {
2656 if (ctxt == NULL)
2657 return(-1);
2658 if (name == NULL)
2659 return(-1);
2660
2661 if (ctxt->funcHash == NULL)
2662 ctxt->funcHash = xmlHashCreate(0);
2663 if (ctxt->funcHash == NULL)
2664 return(-1);
2665 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2666}
2667
2668/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002669 * xmlXPathRegisterFuncLookup:
2670 * @ctxt: the XPath context
2671 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002672 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00002673 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002674 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00002675 */
2676void
2677xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2678 xmlXPathFuncLookupFunc f,
2679 void *funcCtxt) {
2680 if (ctxt == NULL)
2681 return;
2682 ctxt->funcLookupFunc = (void *) f;
2683 ctxt->funcLookupData = funcCtxt;
2684}
2685
2686/**
Owen Taylor3473f882001-02-23 17:55:21 +00002687 * xmlXPathFunctionLookup:
2688 * @ctxt: the XPath context
2689 * @name: the function name
2690 *
2691 * Search in the Function array of the context for the given
2692 * function.
2693 *
2694 * Returns the xmlXPathFunction or NULL if not found
2695 */
2696xmlXPathFunction
2697xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002698 if (ctxt == NULL)
2699 return (NULL);
2700
2701 if (ctxt->funcLookupFunc != NULL) {
2702 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002703 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002704
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002705 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002706 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002707 if (ret != NULL)
2708 return(ret);
2709 }
Owen Taylor3473f882001-02-23 17:55:21 +00002710 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2711}
2712
2713/**
2714 * xmlXPathFunctionLookupNS:
2715 * @ctxt: the XPath context
2716 * @name: the function name
2717 * @ns_uri: the function namespace URI
2718 *
2719 * Search in the Function array of the context for the given
2720 * function.
2721 *
2722 * Returns the xmlXPathFunction or NULL if not found
2723 */
2724xmlXPathFunction
2725xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2726 const xmlChar *ns_uri) {
2727 if (ctxt == NULL)
2728 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002729 if (name == NULL)
2730 return(NULL);
2731
Thomas Broyerba4ad322001-07-26 16:55:21 +00002732 if (ctxt->funcLookupFunc != NULL) {
2733 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002734 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002735
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002736 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002737 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002738 if (ret != NULL)
2739 return(ret);
2740 }
2741
2742 if (ctxt->funcHash == NULL)
2743 return(NULL);
2744
Owen Taylor3473f882001-02-23 17:55:21 +00002745 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2746}
2747
2748/**
2749 * xmlXPathRegisteredFuncsCleanup:
2750 * @ctxt: the XPath context
2751 *
2752 * Cleanup the XPath context data associated to registered functions
2753 */
2754void
2755xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2756 if (ctxt == NULL)
2757 return;
2758
2759 xmlHashFree(ctxt->funcHash, NULL);
2760 ctxt->funcHash = NULL;
2761}
2762
2763/************************************************************************
2764 * *
2765 * Routines to handle Variable *
2766 * *
2767 ************************************************************************/
2768
2769/**
2770 * xmlXPathRegisterVariable:
2771 * @ctxt: the XPath context
2772 * @name: the variable name
2773 * @value: the variable value or NULL
2774 *
2775 * Register a new variable value. If @value is NULL it unregisters
2776 * the variable
2777 *
2778 * Returns 0 in case of success, -1 in case of error
2779 */
2780int
2781xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2782 xmlXPathObjectPtr value) {
2783 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2784}
2785
2786/**
2787 * xmlXPathRegisterVariableNS:
2788 * @ctxt: the XPath context
2789 * @name: the variable name
2790 * @ns_uri: the variable namespace URI
2791 * @value: the variable value or NULL
2792 *
2793 * Register a new variable value. If @value is NULL it unregisters
2794 * the variable
2795 *
2796 * Returns 0 in case of success, -1 in case of error
2797 */
2798int
2799xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2800 const xmlChar *ns_uri,
2801 xmlXPathObjectPtr value) {
2802 if (ctxt == NULL)
2803 return(-1);
2804 if (name == NULL)
2805 return(-1);
2806
2807 if (ctxt->varHash == NULL)
2808 ctxt->varHash = xmlHashCreate(0);
2809 if (ctxt->varHash == NULL)
2810 return(-1);
2811 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2812 (void *) value,
2813 (xmlHashDeallocator)xmlXPathFreeObject));
2814}
2815
2816/**
2817 * xmlXPathRegisterVariableLookup:
2818 * @ctxt: the XPath context
2819 * @f: the lookup function
2820 * @data: the lookup data
2821 *
2822 * register an external mechanism to do variable lookup
2823 */
2824void
2825xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2826 xmlXPathVariableLookupFunc f, void *data) {
2827 if (ctxt == NULL)
2828 return;
2829 ctxt->varLookupFunc = (void *) f;
2830 ctxt->varLookupData = data;
2831}
2832
2833/**
2834 * xmlXPathVariableLookup:
2835 * @ctxt: the XPath context
2836 * @name: the variable name
2837 *
2838 * Search in the Variable array of the context for the given
2839 * variable value.
2840 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002841 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002842 */
2843xmlXPathObjectPtr
2844xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2845 if (ctxt == NULL)
2846 return(NULL);
2847
2848 if (ctxt->varLookupFunc != NULL) {
2849 xmlXPathObjectPtr ret;
2850
2851 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2852 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00002853 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002854 }
2855 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
2856}
2857
2858/**
2859 * xmlXPathVariableLookupNS:
2860 * @ctxt: the XPath context
2861 * @name: the variable name
2862 * @ns_uri: the variable namespace URI
2863 *
2864 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00002865 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00002866 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002867 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002868 */
2869xmlXPathObjectPtr
2870xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2871 const xmlChar *ns_uri) {
2872 if (ctxt == NULL)
2873 return(NULL);
2874
2875 if (ctxt->varLookupFunc != NULL) {
2876 xmlXPathObjectPtr ret;
2877
2878 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2879 (ctxt->varLookupData, name, ns_uri);
2880 if (ret != NULL) return(ret);
2881 }
2882
2883 if (ctxt->varHash == NULL)
2884 return(NULL);
2885 if (name == NULL)
2886 return(NULL);
2887
Daniel Veillard8c357d52001-07-03 23:43:33 +00002888 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
2889 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00002890}
2891
2892/**
2893 * xmlXPathRegisteredVariablesCleanup:
2894 * @ctxt: the XPath context
2895 *
2896 * Cleanup the XPath context data associated to registered variables
2897 */
2898void
2899xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
2900 if (ctxt == NULL)
2901 return;
2902
Daniel Veillard76d66f42001-05-16 21:05:17 +00002903 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00002904 ctxt->varHash = NULL;
2905}
2906
2907/**
2908 * xmlXPathRegisterNs:
2909 * @ctxt: the XPath context
2910 * @prefix: the namespace prefix
2911 * @ns_uri: the namespace name
2912 *
2913 * Register a new namespace. If @ns_uri is NULL it unregisters
2914 * the namespace
2915 *
2916 * Returns 0 in case of success, -1 in case of error
2917 */
2918int
2919xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
2920 const xmlChar *ns_uri) {
2921 if (ctxt == NULL)
2922 return(-1);
2923 if (prefix == NULL)
2924 return(-1);
2925
2926 if (ctxt->nsHash == NULL)
2927 ctxt->nsHash = xmlHashCreate(10);
2928 if (ctxt->nsHash == NULL)
2929 return(-1);
Daniel Veillard42766c02002-08-22 20:52:17 +00002930 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00002931 (xmlHashDeallocator)xmlFree));
2932}
2933
2934/**
2935 * xmlXPathNsLookup:
2936 * @ctxt: the XPath context
2937 * @prefix: the namespace prefix value
2938 *
2939 * Search in the namespace declaration array of the context for the given
2940 * namespace name associated to the given prefix
2941 *
2942 * Returns the value or NULL if not found
2943 */
2944const xmlChar *
2945xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
2946 if (ctxt == NULL)
2947 return(NULL);
2948 if (prefix == NULL)
2949 return(NULL);
2950
2951#ifdef XML_XML_NAMESPACE
2952 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
2953 return(XML_XML_NAMESPACE);
2954#endif
2955
Daniel Veillardc8f620b2001-04-30 20:31:33 +00002956 if (ctxt->namespaces != NULL) {
2957 int i;
2958
2959 for (i = 0;i < ctxt->nsNr;i++) {
2960 if ((ctxt->namespaces[i] != NULL) &&
2961 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
2962 return(ctxt->namespaces[i]->href);
2963 }
2964 }
Owen Taylor3473f882001-02-23 17:55:21 +00002965
2966 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
2967}
2968
2969/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002970 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00002971 * @ctxt: the XPath context
2972 *
2973 * Cleanup the XPath context data associated to registered variables
2974 */
2975void
2976xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
2977 if (ctxt == NULL)
2978 return;
2979
Daniel Veillard42766c02002-08-22 20:52:17 +00002980 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00002981 ctxt->nsHash = NULL;
2982}
2983
2984/************************************************************************
2985 * *
2986 * Routines to handle Values *
2987 * *
2988 ************************************************************************/
2989
2990/* Allocations are terrible, one need to optimize all this !!! */
2991
2992/**
2993 * xmlXPathNewFloat:
2994 * @val: the double value
2995 *
2996 * Create a new xmlXPathObjectPtr of type double and of value @val
2997 *
2998 * Returns the newly created object.
2999 */
3000xmlXPathObjectPtr
3001xmlXPathNewFloat(double val) {
3002 xmlXPathObjectPtr ret;
3003
3004 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3005 if (ret == NULL) {
3006 xmlGenericError(xmlGenericErrorContext,
3007 "xmlXPathNewFloat: out of memory\n");
3008 return(NULL);
3009 }
3010 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3011 ret->type = XPATH_NUMBER;
3012 ret->floatval = val;
3013 return(ret);
3014}
3015
3016/**
3017 * xmlXPathNewBoolean:
3018 * @val: the boolean value
3019 *
3020 * Create a new xmlXPathObjectPtr of type boolean and of value @val
3021 *
3022 * Returns the newly created object.
3023 */
3024xmlXPathObjectPtr
3025xmlXPathNewBoolean(int val) {
3026 xmlXPathObjectPtr ret;
3027
3028 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3029 if (ret == NULL) {
3030 xmlGenericError(xmlGenericErrorContext,
3031 "xmlXPathNewBoolean: out of memory\n");
3032 return(NULL);
3033 }
3034 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3035 ret->type = XPATH_BOOLEAN;
3036 ret->boolval = (val != 0);
3037 return(ret);
3038}
3039
3040/**
3041 * xmlXPathNewString:
3042 * @val: the xmlChar * value
3043 *
3044 * Create a new xmlXPathObjectPtr of type string and of value @val
3045 *
3046 * Returns the newly created object.
3047 */
3048xmlXPathObjectPtr
3049xmlXPathNewString(const xmlChar *val) {
3050 xmlXPathObjectPtr ret;
3051
3052 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3053 if (ret == NULL) {
3054 xmlGenericError(xmlGenericErrorContext,
3055 "xmlXPathNewString: out of memory\n");
3056 return(NULL);
3057 }
3058 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3059 ret->type = XPATH_STRING;
3060 if (val != NULL)
3061 ret->stringval = xmlStrdup(val);
3062 else
3063 ret->stringval = xmlStrdup((const xmlChar *)"");
3064 return(ret);
3065}
3066
3067/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003068 * xmlXPathWrapString:
3069 * @val: the xmlChar * value
3070 *
3071 * Wraps the @val string into an XPath object.
3072 *
3073 * Returns the newly created object.
3074 */
3075xmlXPathObjectPtr
3076xmlXPathWrapString (xmlChar *val) {
3077 xmlXPathObjectPtr ret;
3078
3079 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3080 if (ret == NULL) {
3081 xmlGenericError(xmlGenericErrorContext,
3082 "xmlXPathWrapString: out of memory\n");
3083 return(NULL);
3084 }
3085 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3086 ret->type = XPATH_STRING;
3087 ret->stringval = val;
3088 return(ret);
3089}
3090
3091/**
Owen Taylor3473f882001-02-23 17:55:21 +00003092 * xmlXPathNewCString:
3093 * @val: the char * value
3094 *
3095 * Create a new xmlXPathObjectPtr of type string and of value @val
3096 *
3097 * Returns the newly created object.
3098 */
3099xmlXPathObjectPtr
3100xmlXPathNewCString(const char *val) {
3101 xmlXPathObjectPtr ret;
3102
3103 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3104 if (ret == NULL) {
3105 xmlGenericError(xmlGenericErrorContext,
3106 "xmlXPathNewCString: out of memory\n");
3107 return(NULL);
3108 }
3109 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3110 ret->type = XPATH_STRING;
3111 ret->stringval = xmlStrdup(BAD_CAST val);
3112 return(ret);
3113}
3114
3115/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003116 * xmlXPathWrapCString:
3117 * @val: the char * value
3118 *
3119 * Wraps a string into an XPath object.
3120 *
3121 * Returns the newly created object.
3122 */
3123xmlXPathObjectPtr
3124xmlXPathWrapCString (char * val) {
3125 return(xmlXPathWrapString((xmlChar *)(val)));
3126}
3127
3128/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003129 * xmlXPathWrapExternal:
3130 * @val: the user data
3131 *
3132 * Wraps the @val data into an XPath object.
3133 *
3134 * Returns the newly created object.
3135 */
3136xmlXPathObjectPtr
3137xmlXPathWrapExternal (void *val) {
3138 xmlXPathObjectPtr ret;
3139
3140 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3141 if (ret == NULL) {
3142 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003143 "xmlXPathWrapExternal: out of memory\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003144 return(NULL);
3145 }
3146 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3147 ret->type = XPATH_USERS;
3148 ret->user = val;
3149 return(ret);
3150}
3151
3152/**
Owen Taylor3473f882001-02-23 17:55:21 +00003153 * xmlXPathObjectCopy:
3154 * @val: the original object
3155 *
3156 * allocate a new copy of a given object
3157 *
3158 * Returns the newly created object.
3159 */
3160xmlXPathObjectPtr
3161xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3162 xmlXPathObjectPtr ret;
3163
3164 if (val == NULL)
3165 return(NULL);
3166
3167 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3168 if (ret == NULL) {
3169 xmlGenericError(xmlGenericErrorContext,
3170 "xmlXPathObjectCopy: out of memory\n");
3171 return(NULL);
3172 }
3173 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3174 switch (val->type) {
3175 case XPATH_BOOLEAN:
3176 case XPATH_NUMBER:
3177 case XPATH_POINT:
3178 case XPATH_RANGE:
3179 break;
3180 case XPATH_STRING:
3181 ret->stringval = xmlStrdup(val->stringval);
3182 break;
3183 case XPATH_XSLT_TREE:
3184 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003185 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003186 xmlNodePtr cur, tmp;
3187 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003188
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003189 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00003190 top = xmlNewDoc(NULL);
3191 top->name = (char *)
3192 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003193 ret->user = top;
3194 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003195 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003196 cur = val->nodesetval->nodeTab[0]->children;
3197 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003198 tmp = xmlDocCopyNode(cur, top, 1);
3199 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003200 cur = cur->next;
3201 }
3202 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003203 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003204 } else
Owen Taylor3473f882001-02-23 17:55:21 +00003205 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003206 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00003207 break;
3208 case XPATH_NODESET:
3209 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003210 /* Do not deallocate the copied tree value */
3211 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003212 break;
3213 case XPATH_LOCATIONSET:
3214#ifdef LIBXML_XPTR_ENABLED
3215 {
3216 xmlLocationSetPtr loc = val->user;
3217 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3218 break;
3219 }
3220#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00003221 case XPATH_USERS:
3222 ret->user = val->user;
3223 break;
3224 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00003225 xmlGenericError(xmlGenericErrorContext,
3226 "xmlXPathObjectCopy: unsupported type %d\n",
3227 val->type);
3228 break;
3229 }
3230 return(ret);
3231}
3232
3233/**
3234 * xmlXPathFreeObject:
3235 * @obj: the object to free
3236 *
3237 * Free up an xmlXPathObjectPtr object.
3238 */
3239void
3240xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3241 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003242 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00003243 if (obj->boolval) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003244 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003245 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00003246 xmlFreeNodeList((xmlNodePtr) obj->user);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003247 } else if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00003248 xmlXPathFreeValueTree(obj->nodesetval);
3249 } else {
3250 if (obj->nodesetval != NULL)
3251 xmlXPathFreeNodeSet(obj->nodesetval);
3252 }
Owen Taylor3473f882001-02-23 17:55:21 +00003253#ifdef LIBXML_XPTR_ENABLED
3254 } else if (obj->type == XPATH_LOCATIONSET) {
3255 if (obj->user != NULL)
3256 xmlXPtrFreeLocationSet(obj->user);
3257#endif
3258 } else if (obj->type == XPATH_STRING) {
3259 if (obj->stringval != NULL)
3260 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00003261 }
3262
Owen Taylor3473f882001-02-23 17:55:21 +00003263 xmlFree(obj);
3264}
3265
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003266
3267/************************************************************************
3268 * *
3269 * Type Casting Routines *
3270 * *
3271 ************************************************************************/
3272
3273/**
3274 * xmlXPathCastBooleanToString:
3275 * @val: a boolean
3276 *
3277 * Converts a boolean to its string value.
3278 *
3279 * Returns a newly allocated string.
3280 */
3281xmlChar *
3282xmlXPathCastBooleanToString (int val) {
3283 xmlChar *ret;
3284 if (val)
3285 ret = xmlStrdup((const xmlChar *) "true");
3286 else
3287 ret = xmlStrdup((const xmlChar *) "false");
3288 return(ret);
3289}
3290
3291/**
3292 * xmlXPathCastNumberToString:
3293 * @val: a number
3294 *
3295 * Converts a number to its string value.
3296 *
3297 * Returns a newly allocated string.
3298 */
3299xmlChar *
3300xmlXPathCastNumberToString (double val) {
3301 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00003302 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003303 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003304 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003305 break;
3306 case -1:
3307 ret = xmlStrdup((const xmlChar *) "-Infinity");
3308 break;
3309 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003310 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003311 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00003312 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
3313 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003314 } else {
3315 /* could be improved */
3316 char buf[100];
3317 xmlXPathFormatNumber(val, buf, 100);
3318 ret = xmlStrdup((const xmlChar *) buf);
3319 }
3320 }
3321 return(ret);
3322}
3323
3324/**
3325 * xmlXPathCastNodeToString:
3326 * @node: a node
3327 *
3328 * Converts a node to its string value.
3329 *
3330 * Returns a newly allocated string.
3331 */
3332xmlChar *
3333xmlXPathCastNodeToString (xmlNodePtr node) {
3334 return(xmlNodeGetContent(node));
3335}
3336
3337/**
3338 * xmlXPathCastNodeSetToString:
3339 * @ns: a node-set
3340 *
3341 * Converts a node-set to its string value.
3342 *
3343 * Returns a newly allocated string.
3344 */
3345xmlChar *
3346xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3347 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3348 return(xmlStrdup((const xmlChar *) ""));
3349
3350 xmlXPathNodeSetSort(ns);
3351 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3352}
3353
3354/**
3355 * xmlXPathCastToString:
3356 * @val: an XPath object
3357 *
3358 * Converts an existing object to its string() equivalent
3359 *
3360 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003361 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003362 * string object).
3363 */
3364xmlChar *
3365xmlXPathCastToString(xmlXPathObjectPtr val) {
3366 xmlChar *ret = NULL;
3367
3368 if (val == NULL)
3369 return(xmlStrdup((const xmlChar *) ""));
3370 switch (val->type) {
3371 case XPATH_UNDEFINED:
3372#ifdef DEBUG_EXPR
3373 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3374#endif
3375 ret = xmlStrdup((const xmlChar *) "");
3376 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003377 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003378 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003379 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3380 break;
3381 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00003382 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003383 case XPATH_BOOLEAN:
3384 ret = xmlXPathCastBooleanToString(val->boolval);
3385 break;
3386 case XPATH_NUMBER: {
3387 ret = xmlXPathCastNumberToString(val->floatval);
3388 break;
3389 }
3390 case XPATH_USERS:
3391 case XPATH_POINT:
3392 case XPATH_RANGE:
3393 case XPATH_LOCATIONSET:
3394 TODO
3395 ret = xmlStrdup((const xmlChar *) "");
3396 break;
3397 }
3398 return(ret);
3399}
3400
3401/**
3402 * xmlXPathConvertString:
3403 * @val: an XPath object
3404 *
3405 * Converts an existing object to its string() equivalent
3406 *
3407 * Returns the new object, the old one is freed (or the operation
3408 * is done directly on @val)
3409 */
3410xmlXPathObjectPtr
3411xmlXPathConvertString(xmlXPathObjectPtr val) {
3412 xmlChar *res = NULL;
3413
3414 if (val == NULL)
3415 return(xmlXPathNewCString(""));
3416
3417 switch (val->type) {
3418 case XPATH_UNDEFINED:
3419#ifdef DEBUG_EXPR
3420 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3421#endif
3422 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003423 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003424 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003425 res = xmlXPathCastNodeSetToString(val->nodesetval);
3426 break;
3427 case XPATH_STRING:
3428 return(val);
3429 case XPATH_BOOLEAN:
3430 res = xmlXPathCastBooleanToString(val->boolval);
3431 break;
3432 case XPATH_NUMBER:
3433 res = xmlXPathCastNumberToString(val->floatval);
3434 break;
3435 case XPATH_USERS:
3436 case XPATH_POINT:
3437 case XPATH_RANGE:
3438 case XPATH_LOCATIONSET:
3439 TODO;
3440 break;
3441 }
3442 xmlXPathFreeObject(val);
3443 if (res == NULL)
3444 return(xmlXPathNewCString(""));
3445 return(xmlXPathWrapString(res));
3446}
3447
3448/**
3449 * xmlXPathCastBooleanToNumber:
3450 * @val: a boolean
3451 *
3452 * Converts a boolean to its number value
3453 *
3454 * Returns the number value
3455 */
3456double
3457xmlXPathCastBooleanToNumber(int val) {
3458 if (val)
3459 return(1.0);
3460 return(0.0);
3461}
3462
3463/**
3464 * xmlXPathCastStringToNumber:
3465 * @val: a string
3466 *
3467 * Converts a string to its number value
3468 *
3469 * Returns the number value
3470 */
3471double
3472xmlXPathCastStringToNumber(const xmlChar * val) {
3473 return(xmlXPathStringEvalNumber(val));
3474}
3475
3476/**
3477 * xmlXPathCastNodeToNumber:
3478 * @node: a node
3479 *
3480 * Converts a node to its number value
3481 *
3482 * Returns the number value
3483 */
3484double
3485xmlXPathCastNodeToNumber (xmlNodePtr node) {
3486 xmlChar *strval;
3487 double ret;
3488
3489 if (node == NULL)
3490 return(xmlXPathNAN);
3491 strval = xmlXPathCastNodeToString(node);
3492 if (strval == NULL)
3493 return(xmlXPathNAN);
3494 ret = xmlXPathCastStringToNumber(strval);
3495 xmlFree(strval);
3496
3497 return(ret);
3498}
3499
3500/**
3501 * xmlXPathCastNodeSetToNumber:
3502 * @ns: a node-set
3503 *
3504 * Converts a node-set to its number value
3505 *
3506 * Returns the number value
3507 */
3508double
3509xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3510 xmlChar *str;
3511 double ret;
3512
3513 if (ns == NULL)
3514 return(xmlXPathNAN);
3515 str = xmlXPathCastNodeSetToString(ns);
3516 ret = xmlXPathCastStringToNumber(str);
3517 xmlFree(str);
3518 return(ret);
3519}
3520
3521/**
3522 * xmlXPathCastToNumber:
3523 * @val: an XPath object
3524 *
3525 * Converts an XPath object to its number value
3526 *
3527 * Returns the number value
3528 */
3529double
3530xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3531 double ret = 0.0;
3532
3533 if (val == NULL)
3534 return(xmlXPathNAN);
3535 switch (val->type) {
3536 case XPATH_UNDEFINED:
3537#ifdef DEGUB_EXPR
3538 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3539#endif
3540 ret = xmlXPathNAN;
3541 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003542 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003543 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003544 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3545 break;
3546 case XPATH_STRING:
3547 ret = xmlXPathCastStringToNumber(val->stringval);
3548 break;
3549 case XPATH_NUMBER:
3550 ret = val->floatval;
3551 break;
3552 case XPATH_BOOLEAN:
3553 ret = xmlXPathCastBooleanToNumber(val->boolval);
3554 break;
3555 case XPATH_USERS:
3556 case XPATH_POINT:
3557 case XPATH_RANGE:
3558 case XPATH_LOCATIONSET:
3559 TODO;
3560 ret = xmlXPathNAN;
3561 break;
3562 }
3563 return(ret);
3564}
3565
3566/**
3567 * xmlXPathConvertNumber:
3568 * @val: an XPath object
3569 *
3570 * Converts an existing object to its number() equivalent
3571 *
3572 * Returns the new object, the old one is freed (or the operation
3573 * is done directly on @val)
3574 */
3575xmlXPathObjectPtr
3576xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3577 xmlXPathObjectPtr ret;
3578
3579 if (val == NULL)
3580 return(xmlXPathNewFloat(0.0));
3581 if (val->type == XPATH_NUMBER)
3582 return(val);
3583 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3584 xmlXPathFreeObject(val);
3585 return(ret);
3586}
3587
3588/**
3589 * xmlXPathCastNumberToBoolean:
3590 * @val: a number
3591 *
3592 * Converts a number to its boolean value
3593 *
3594 * Returns the boolean value
3595 */
3596int
3597xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003598 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003599 return(0);
3600 return(1);
3601}
3602
3603/**
3604 * xmlXPathCastStringToBoolean:
3605 * @val: a string
3606 *
3607 * Converts a string to its boolean value
3608 *
3609 * Returns the boolean value
3610 */
3611int
3612xmlXPathCastStringToBoolean (const xmlChar *val) {
3613 if ((val == NULL) || (xmlStrlen(val) == 0))
3614 return(0);
3615 return(1);
3616}
3617
3618/**
3619 * xmlXPathCastNodeSetToBoolean:
3620 * @ns: a node-set
3621 *
3622 * Converts a node-set to its boolean value
3623 *
3624 * Returns the boolean value
3625 */
3626int
3627xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3628 if ((ns == NULL) || (ns->nodeNr == 0))
3629 return(0);
3630 return(1);
3631}
3632
3633/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003634 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003635 * @val: an XPath object
3636 *
3637 * Converts an XPath object to its boolean value
3638 *
3639 * Returns the boolean value
3640 */
3641int
3642xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3643 int ret = 0;
3644
3645 if (val == NULL)
3646 return(0);
3647 switch (val->type) {
3648 case XPATH_UNDEFINED:
3649#ifdef DEBUG_EXPR
3650 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3651#endif
3652 ret = 0;
3653 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003654 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003655 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003656 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3657 break;
3658 case XPATH_STRING:
3659 ret = xmlXPathCastStringToBoolean(val->stringval);
3660 break;
3661 case XPATH_NUMBER:
3662 ret = xmlXPathCastNumberToBoolean(val->floatval);
3663 break;
3664 case XPATH_BOOLEAN:
3665 ret = val->boolval;
3666 break;
3667 case XPATH_USERS:
3668 case XPATH_POINT:
3669 case XPATH_RANGE:
3670 case XPATH_LOCATIONSET:
3671 TODO;
3672 ret = 0;
3673 break;
3674 }
3675 return(ret);
3676}
3677
3678
3679/**
3680 * xmlXPathConvertBoolean:
3681 * @val: an XPath object
3682 *
3683 * Converts an existing object to its boolean() equivalent
3684 *
3685 * Returns the new object, the old one is freed (or the operation
3686 * is done directly on @val)
3687 */
3688xmlXPathObjectPtr
3689xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3690 xmlXPathObjectPtr ret;
3691
3692 if (val == NULL)
3693 return(xmlXPathNewBoolean(0));
3694 if (val->type == XPATH_BOOLEAN)
3695 return(val);
3696 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3697 xmlXPathFreeObject(val);
3698 return(ret);
3699}
3700
Owen Taylor3473f882001-02-23 17:55:21 +00003701/************************************************************************
3702 * *
3703 * Routines to handle XPath contexts *
3704 * *
3705 ************************************************************************/
3706
3707/**
3708 * xmlXPathNewContext:
3709 * @doc: the XML document
3710 *
3711 * Create a new xmlXPathContext
3712 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00003713 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00003714 */
3715xmlXPathContextPtr
3716xmlXPathNewContext(xmlDocPtr doc) {
3717 xmlXPathContextPtr ret;
3718
3719 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3720 if (ret == NULL) {
3721 xmlGenericError(xmlGenericErrorContext,
3722 "xmlXPathNewContext: out of memory\n");
3723 return(NULL);
3724 }
3725 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3726 ret->doc = doc;
3727 ret->node = NULL;
3728
3729 ret->varHash = NULL;
3730
3731 ret->nb_types = 0;
3732 ret->max_types = 0;
3733 ret->types = NULL;
3734
3735 ret->funcHash = xmlHashCreate(0);
3736
3737 ret->nb_axis = 0;
3738 ret->max_axis = 0;
3739 ret->axis = NULL;
3740
3741 ret->nsHash = NULL;
3742 ret->user = NULL;
3743
3744 ret->contextSize = -1;
3745 ret->proximityPosition = -1;
3746
3747 xmlXPathRegisterAllFunctions(ret);
3748
3749 return(ret);
3750}
3751
3752/**
3753 * xmlXPathFreeContext:
3754 * @ctxt: the context to free
3755 *
3756 * Free up an xmlXPathContext
3757 */
3758void
3759xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3760 xmlXPathRegisteredNsCleanup(ctxt);
3761 xmlXPathRegisteredFuncsCleanup(ctxt);
3762 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003763 xmlFree(ctxt);
3764}
3765
3766/************************************************************************
3767 * *
3768 * Routines to handle XPath parser contexts *
3769 * *
3770 ************************************************************************/
3771
3772#define CHECK_CTXT(ctxt) \
3773 if (ctxt == NULL) { \
3774 xmlGenericError(xmlGenericErrorContext, \
3775 "%s:%d Internal error: ctxt == NULL\n", \
3776 __FILE__, __LINE__); \
3777 } \
3778
3779
3780#define CHECK_CONTEXT(ctxt) \
3781 if (ctxt == NULL) { \
3782 xmlGenericError(xmlGenericErrorContext, \
3783 "%s:%d Internal error: no context\n", \
3784 __FILE__, __LINE__); \
3785 } \
3786 else if (ctxt->doc == NULL) { \
3787 xmlGenericError(xmlGenericErrorContext, \
3788 "%s:%d Internal error: no document\n", \
3789 __FILE__, __LINE__); \
3790 } \
3791 else if (ctxt->doc->children == NULL) { \
3792 xmlGenericError(xmlGenericErrorContext, \
3793 "%s:%d Internal error: document without root\n", \
3794 __FILE__, __LINE__); \
3795 } \
3796
3797
3798/**
3799 * xmlXPathNewParserContext:
3800 * @str: the XPath expression
3801 * @ctxt: the XPath context
3802 *
3803 * Create a new xmlXPathParserContext
3804 *
3805 * Returns the xmlXPathParserContext just allocated.
3806 */
3807xmlXPathParserContextPtr
3808xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3809 xmlXPathParserContextPtr ret;
3810
3811 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3812 if (ret == NULL) {
3813 xmlGenericError(xmlGenericErrorContext,
3814 "xmlXPathNewParserContext: out of memory\n");
3815 return(NULL);
3816 }
3817 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3818 ret->cur = ret->base = str;
3819 ret->context = ctxt;
3820
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003821 ret->comp = xmlXPathNewCompExpr();
3822 if (ret->comp == NULL) {
3823 xmlFree(ret->valueTab);
3824 xmlFree(ret);
3825 return(NULL);
3826 }
3827
3828 return(ret);
3829}
3830
3831/**
3832 * xmlXPathCompParserContext:
3833 * @comp: the XPath compiled expression
3834 * @ctxt: the XPath context
3835 *
3836 * Create a new xmlXPathParserContext when processing a compiled expression
3837 *
3838 * Returns the xmlXPathParserContext just allocated.
3839 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003840static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003841xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3842 xmlXPathParserContextPtr ret;
3843
3844 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3845 if (ret == NULL) {
3846 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003847 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003848 return(NULL);
3849 }
3850 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3851
Owen Taylor3473f882001-02-23 17:55:21 +00003852 /* Allocate the value stack */
3853 ret->valueTab = (xmlXPathObjectPtr *)
3854 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003855 if (ret->valueTab == NULL) {
3856 xmlFree(ret);
3857 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003858 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003859 return(NULL);
3860 }
Owen Taylor3473f882001-02-23 17:55:21 +00003861 ret->valueNr = 0;
3862 ret->valueMax = 10;
3863 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003864
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00003865 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003866 ret->comp = comp;
3867
Owen Taylor3473f882001-02-23 17:55:21 +00003868 return(ret);
3869}
3870
3871/**
3872 * xmlXPathFreeParserContext:
3873 * @ctxt: the context to free
3874 *
3875 * Free up an xmlXPathParserContext
3876 */
3877void
3878xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
3879 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003880 xmlFree(ctxt->valueTab);
3881 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003882 if (ctxt->comp)
3883 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00003884 xmlFree(ctxt);
3885}
3886
3887/************************************************************************
3888 * *
3889 * The implicit core function library *
3890 * *
3891 ************************************************************************/
3892
Owen Taylor3473f882001-02-23 17:55:21 +00003893/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00003894 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00003895 * @node: a node pointer
3896 *
3897 * Function computing the beginning of the string value of the node,
3898 * used to speed up comparisons
3899 *
3900 * Returns an int usable as a hash
3901 */
3902static unsigned int
3903xmlXPathNodeValHash(xmlNodePtr node) {
3904 int len = 2;
3905 const xmlChar * string = NULL;
3906 xmlNodePtr tmp = NULL;
3907 unsigned int ret = 0;
3908
3909 if (node == NULL)
3910 return(0);
3911
Daniel Veillard9adc0462003-03-24 18:39:54 +00003912 if (node->type == XML_DOCUMENT_NODE) {
3913 tmp = xmlDocGetRootElement((xmlDocPtr) node);
3914 if (tmp == NULL)
3915 node = node->children;
3916 else
3917 node = tmp;
3918
3919 if (node == NULL)
3920 return(0);
3921 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003922
3923 switch (node->type) {
3924 case XML_COMMENT_NODE:
3925 case XML_PI_NODE:
3926 case XML_CDATA_SECTION_NODE:
3927 case XML_TEXT_NODE:
3928 string = node->content;
3929 if (string == NULL)
3930 return(0);
3931 if (string[0] == 0)
3932 return(0);
3933 return(((unsigned int) string[0]) +
3934 (((unsigned int) string[1]) << 8));
3935 case XML_NAMESPACE_DECL:
3936 string = ((xmlNsPtr)node)->href;
3937 if (string == NULL)
3938 return(0);
3939 if (string[0] == 0)
3940 return(0);
3941 return(((unsigned int) string[0]) +
3942 (((unsigned int) string[1]) << 8));
3943 case XML_ATTRIBUTE_NODE:
3944 tmp = ((xmlAttrPtr) node)->children;
3945 break;
3946 case XML_ELEMENT_NODE:
3947 tmp = node->children;
3948 break;
3949 default:
3950 return(0);
3951 }
3952 while (tmp != NULL) {
3953 switch (tmp->type) {
3954 case XML_COMMENT_NODE:
3955 case XML_PI_NODE:
3956 case XML_CDATA_SECTION_NODE:
3957 case XML_TEXT_NODE:
3958 string = tmp->content;
3959 break;
3960 case XML_NAMESPACE_DECL:
3961 string = ((xmlNsPtr)tmp)->href;
3962 break;
3963 default:
3964 break;
3965 }
3966 if ((string != NULL) && (string[0] != 0)) {
3967 if (string[0] == 0)
3968 return(0);
3969 if (len == 1) {
3970 return(ret + (((unsigned int) string[0]) << 8));
3971 }
3972 if (string[1] == 0) {
3973 len = 1;
3974 ret = (unsigned int) string[0];
3975 } else {
3976 return(((unsigned int) string[0]) +
3977 (((unsigned int) string[1]) << 8));
3978 }
3979 }
3980 /*
3981 * Skip to next node
3982 */
3983 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
3984 if (tmp->children->type != XML_ENTITY_DECL) {
3985 tmp = tmp->children;
3986 continue;
3987 }
3988 }
3989 if (tmp == node)
3990 break;
3991
3992 if (tmp->next != NULL) {
3993 tmp = tmp->next;
3994 continue;
3995 }
3996
3997 do {
3998 tmp = tmp->parent;
3999 if (tmp == NULL)
4000 break;
4001 if (tmp == node) {
4002 tmp = NULL;
4003 break;
4004 }
4005 if (tmp->next != NULL) {
4006 tmp = tmp->next;
4007 break;
4008 }
4009 } while (tmp != NULL);
4010 }
4011 return(ret);
4012}
4013
4014/**
4015 * xmlXPathStringHash:
4016 * @string: a string
4017 *
4018 * Function computing the beginning of the string value of the node,
4019 * used to speed up comparisons
4020 *
4021 * Returns an int usable as a hash
4022 */
4023static unsigned int
4024xmlXPathStringHash(const xmlChar * string) {
4025 if (string == NULL)
4026 return((unsigned int) 0);
4027 if (string[0] == 0)
4028 return(0);
4029 return(((unsigned int) string[0]) +
4030 (((unsigned int) string[1]) << 8));
4031}
4032
4033/**
Owen Taylor3473f882001-02-23 17:55:21 +00004034 * xmlXPathCompareNodeSetFloat:
4035 * @ctxt: the XPath Parser context
4036 * @inf: less than (1) or greater than (0)
4037 * @strict: is the comparison strict
4038 * @arg: the node set
4039 * @f: the value
4040 *
4041 * Implement the compare operation between a nodeset and a number
4042 * @ns < @val (1, 1, ...
4043 * @ns <= @val (1, 0, ...
4044 * @ns > @val (0, 1, ...
4045 * @ns >= @val (0, 0, ...
4046 *
4047 * If one object to be compared is a node-set and the other is a number,
4048 * then the comparison will be true if and only if there is a node in the
4049 * node-set such that the result of performing the comparison on the number
4050 * to be compared and on the result of converting the string-value of that
4051 * node to a number using the number function is true.
4052 *
4053 * Returns 0 or 1 depending on the results of the test.
4054 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004055static int
Owen Taylor3473f882001-02-23 17:55:21 +00004056xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
4057 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
4058 int i, ret = 0;
4059 xmlNodeSetPtr ns;
4060 xmlChar *str2;
4061
4062 if ((f == NULL) || (arg == NULL) ||
4063 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4064 xmlXPathFreeObject(arg);
4065 xmlXPathFreeObject(f);
4066 return(0);
4067 }
4068 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004069 if (ns != NULL) {
4070 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004071 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004072 if (str2 != NULL) {
4073 valuePush(ctxt,
4074 xmlXPathNewString(str2));
4075 xmlFree(str2);
4076 xmlXPathNumberFunction(ctxt, 1);
4077 valuePush(ctxt, xmlXPathObjectCopy(f));
4078 ret = xmlXPathCompareValues(ctxt, inf, strict);
4079 if (ret)
4080 break;
4081 }
4082 }
Owen Taylor3473f882001-02-23 17:55:21 +00004083 }
4084 xmlXPathFreeObject(arg);
4085 xmlXPathFreeObject(f);
4086 return(ret);
4087}
4088
4089/**
4090 * xmlXPathCompareNodeSetString:
4091 * @ctxt: the XPath Parser context
4092 * @inf: less than (1) or greater than (0)
4093 * @strict: is the comparison strict
4094 * @arg: the node set
4095 * @s: the value
4096 *
4097 * Implement the compare operation between a nodeset and a string
4098 * @ns < @val (1, 1, ...
4099 * @ns <= @val (1, 0, ...
4100 * @ns > @val (0, 1, ...
4101 * @ns >= @val (0, 0, ...
4102 *
4103 * If one object to be compared is a node-set and the other is a string,
4104 * then the comparison will be true if and only if there is a node in
4105 * the node-set such that the result of performing the comparison on the
4106 * string-value of the node and the other string is true.
4107 *
4108 * Returns 0 or 1 depending on the results of the test.
4109 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004110static int
Owen Taylor3473f882001-02-23 17:55:21 +00004111xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
4112 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
4113 int i, ret = 0;
4114 xmlNodeSetPtr ns;
4115 xmlChar *str2;
4116
4117 if ((s == NULL) || (arg == NULL) ||
4118 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4119 xmlXPathFreeObject(arg);
4120 xmlXPathFreeObject(s);
4121 return(0);
4122 }
4123 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004124 if (ns != NULL) {
4125 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004126 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004127 if (str2 != NULL) {
4128 valuePush(ctxt,
4129 xmlXPathNewString(str2));
4130 xmlFree(str2);
4131 valuePush(ctxt, xmlXPathObjectCopy(s));
4132 ret = xmlXPathCompareValues(ctxt, inf, strict);
4133 if (ret)
4134 break;
4135 }
4136 }
Owen Taylor3473f882001-02-23 17:55:21 +00004137 }
4138 xmlXPathFreeObject(arg);
4139 xmlXPathFreeObject(s);
4140 return(ret);
4141}
4142
4143/**
4144 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004145 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00004146 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004147 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00004148 * @arg2: the second node set object
4149 *
4150 * Implement the compare operation on nodesets:
4151 *
4152 * If both objects to be compared are node-sets, then the comparison
4153 * will be true if and only if there is a node in the first node-set
4154 * and a node in the second node-set such that the result of performing
4155 * the comparison on the string-values of the two nodes is true.
4156 * ....
4157 * When neither object to be compared is a node-set and the operator
4158 * is <=, <, >= or >, then the objects are compared by converting both
4159 * objects to numbers and comparing the numbers according to IEEE 754.
4160 * ....
4161 * The number function converts its argument to a number as follows:
4162 * - a string that consists of optional whitespace followed by an
4163 * optional minus sign followed by a Number followed by whitespace
4164 * is converted to the IEEE 754 number that is nearest (according
4165 * to the IEEE 754 round-to-nearest rule) to the mathematical value
4166 * represented by the string; any other string is converted to NaN
4167 *
4168 * Conclusion all nodes need to be converted first to their string value
4169 * and then the comparison must be done when possible
4170 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004171static int
4172xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00004173 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4174 int i, j, init = 0;
4175 double val1;
4176 double *values2;
4177 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004178 xmlNodeSetPtr ns1;
4179 xmlNodeSetPtr ns2;
4180
4181 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004182 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4183 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004184 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004185 }
Owen Taylor3473f882001-02-23 17:55:21 +00004186 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004187 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4188 xmlXPathFreeObject(arg1);
4189 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004190 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004191 }
Owen Taylor3473f882001-02-23 17:55:21 +00004192
4193 ns1 = arg1->nodesetval;
4194 ns2 = arg2->nodesetval;
4195
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004196 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004197 xmlXPathFreeObject(arg1);
4198 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004199 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004200 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004201 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004202 xmlXPathFreeObject(arg1);
4203 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004204 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004205 }
Owen Taylor3473f882001-02-23 17:55:21 +00004206
4207 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4208 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004209 xmlXPathFreeObject(arg1);
4210 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004211 return(0);
4212 }
4213 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004214 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004215 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004216 continue;
4217 for (j = 0;j < ns2->nodeNr;j++) {
4218 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004219 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004220 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004221 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004222 continue;
4223 if (inf && strict)
4224 ret = (val1 < values2[j]);
4225 else if (inf && !strict)
4226 ret = (val1 <= values2[j]);
4227 else if (!inf && strict)
4228 ret = (val1 > values2[j]);
4229 else if (!inf && !strict)
4230 ret = (val1 >= values2[j]);
4231 if (ret)
4232 break;
4233 }
4234 if (ret)
4235 break;
4236 init = 1;
4237 }
4238 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004239 xmlXPathFreeObject(arg1);
4240 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004241 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004242}
4243
4244/**
4245 * xmlXPathCompareNodeSetValue:
4246 * @ctxt: the XPath Parser context
4247 * @inf: less than (1) or greater than (0)
4248 * @strict: is the comparison strict
4249 * @arg: the node set
4250 * @val: the value
4251 *
4252 * Implement the compare operation between a nodeset and a value
4253 * @ns < @val (1, 1, ...
4254 * @ns <= @val (1, 0, ...
4255 * @ns > @val (0, 1, ...
4256 * @ns >= @val (0, 0, ...
4257 *
4258 * If one object to be compared is a node-set and the other is a boolean,
4259 * then the comparison will be true if and only if the result of performing
4260 * the comparison on the boolean and on the result of converting
4261 * the node-set to a boolean using the boolean function is true.
4262 *
4263 * Returns 0 or 1 depending on the results of the test.
4264 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004265static int
Owen Taylor3473f882001-02-23 17:55:21 +00004266xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4267 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4268 if ((val == NULL) || (arg == NULL) ||
4269 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4270 return(0);
4271
4272 switch(val->type) {
4273 case XPATH_NUMBER:
4274 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4275 case XPATH_NODESET:
4276 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004277 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004278 case XPATH_STRING:
4279 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4280 case XPATH_BOOLEAN:
4281 valuePush(ctxt, arg);
4282 xmlXPathBooleanFunction(ctxt, 1);
4283 valuePush(ctxt, val);
4284 return(xmlXPathCompareValues(ctxt, inf, strict));
4285 default:
4286 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004287 }
4288 return(0);
4289}
4290
4291/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004292 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00004293 * @arg: the nodeset object argument
4294 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00004295 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004296 *
4297 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4298 * If one object to be compared is a node-set and the other is a string,
4299 * then the comparison will be true if and only if there is a node in
4300 * the node-set such that the result of performing the comparison on the
4301 * string-value of the node and the other string is true.
4302 *
4303 * Returns 0 or 1 depending on the results of the test.
4304 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004305static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004306xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004307{
Owen Taylor3473f882001-02-23 17:55:21 +00004308 int i;
4309 xmlNodeSetPtr ns;
4310 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004311 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004312
4313 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004314 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4315 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004316 ns = arg->nodesetval;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004317 hash = xmlXPathStringHash(str);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004318 if (ns == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004319 return (0);
Daniel Veillard73c9c042001-07-05 20:02:54 +00004320 if (ns->nodeNr <= 0) {
4321 if (hash == 0)
William M. Brack0c022ad2002-07-12 00:56:01 +00004322 return(neq ^ 1);
4323 return(neq);
Daniel Veillard73c9c042001-07-05 20:02:54 +00004324 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004325 for (i = 0; i < ns->nodeNr; i++) {
4326 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4327 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4328 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4329 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004330 if (neq)
4331 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004332 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00004333 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
4334 if (neq)
4335 continue;
4336 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00004337 } else if (neq) {
4338 if (str2 != NULL)
4339 xmlFree(str2);
4340 return (1);
4341 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004342 if (str2 != NULL)
4343 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004344 } else if (neq)
4345 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00004346 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004347 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004348}
4349
4350/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004351 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00004352 * @arg: the nodeset object argument
4353 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00004354 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004355 *
4356 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4357 * If one object to be compared is a node-set and the other is a number,
4358 * then the comparison will be true if and only if there is a node in
4359 * the node-set such that the result of performing the comparison on the
4360 * number to be compared and on the result of converting the string-value
4361 * of that node to a number using the number function is true.
4362 *
4363 * Returns 0 or 1 depending on the results of the test.
4364 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004365static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004366xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
4367 xmlXPathObjectPtr arg, double f, int neq) {
4368 int i, ret=0;
4369 xmlNodeSetPtr ns;
4370 xmlChar *str2;
4371 xmlXPathObjectPtr val;
4372 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00004373
4374 if ((arg == NULL) ||
4375 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4376 return(0);
4377
William M. Brack0c022ad2002-07-12 00:56:01 +00004378 ns = arg->nodesetval;
4379 if (ns != NULL) {
4380 for (i=0;i<ns->nodeNr;i++) {
4381 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4382 if (str2 != NULL) {
4383 valuePush(ctxt, xmlXPathNewString(str2));
4384 xmlFree(str2);
4385 xmlXPathNumberFunction(ctxt, 1);
4386 val = valuePop(ctxt);
4387 v = val->floatval;
4388 xmlXPathFreeObject(val);
4389 if (!xmlXPathIsNaN(v)) {
4390 if ((!neq) && (v==f)) {
4391 ret = 1;
4392 break;
4393 } else if ((neq) && (v!=f)) {
4394 ret = 1;
4395 break;
4396 }
4397 }
4398 }
4399 }
4400 }
4401
4402 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004403}
4404
4405
4406/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004407 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00004408 * @arg1: first nodeset object argument
4409 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00004410 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004411 *
William M. Brack0c022ad2002-07-12 00:56:01 +00004412 * Implement the equal / not equal operation on XPath nodesets:
4413 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00004414 * If both objects to be compared are node-sets, then the comparison
4415 * will be true if and only if there is a node in the first node-set and
4416 * a node in the second node-set such that the result of performing the
4417 * comparison on the string-values of the two nodes is true.
4418 *
4419 * (needless to say, this is a costly operation)
4420 *
4421 * Returns 0 or 1 depending on the results of the test.
4422 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004423static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004424xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00004425 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004426 unsigned int *hashs1;
4427 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004428 xmlChar **values1;
4429 xmlChar **values2;
4430 int ret = 0;
4431 xmlNodeSetPtr ns1;
4432 xmlNodeSetPtr ns2;
4433
4434 if ((arg1 == NULL) ||
4435 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4436 return(0);
4437 if ((arg2 == NULL) ||
4438 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4439 return(0);
4440
4441 ns1 = arg1->nodesetval;
4442 ns2 = arg2->nodesetval;
4443
Daniel Veillard911f49a2001-04-07 15:39:35 +00004444 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004445 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004446 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004447 return(0);
4448
4449 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00004450 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00004451 */
William M. Brack0c022ad2002-07-12 00:56:01 +00004452 if (neq == 0)
4453 for (i = 0;i < ns1->nodeNr;i++)
4454 for (j = 0;j < ns2->nodeNr;j++)
4455 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4456 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00004457
4458 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
4459 if (values1 == NULL)
4460 return(0);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004461 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4462 if (hashs1 == NULL) {
4463 xmlFree(values1);
4464 return(0);
4465 }
Owen Taylor3473f882001-02-23 17:55:21 +00004466 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4467 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4468 if (values2 == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004469 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004470 xmlFree(values1);
4471 return(0);
4472 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004473 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4474 if (hashs2 == NULL) {
4475 xmlFree(hashs1);
4476 xmlFree(values1);
4477 xmlFree(values2);
4478 return(0);
4479 }
Owen Taylor3473f882001-02-23 17:55:21 +00004480 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4481 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004482 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004483 for (j = 0;j < ns2->nodeNr;j++) {
4484 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004485 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004486 if (hashs1[i] != hashs2[j]) {
4487 if (neq) {
4488 ret = 1;
4489 break;
4490 }
4491 }
4492 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004493 if (values1[i] == NULL)
4494 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4495 if (values2[j] == NULL)
4496 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004497 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004498 if (ret)
4499 break;
4500 }
Owen Taylor3473f882001-02-23 17:55:21 +00004501 }
4502 if (ret)
4503 break;
4504 }
4505 for (i = 0;i < ns1->nodeNr;i++)
4506 if (values1[i] != NULL)
4507 xmlFree(values1[i]);
4508 for (j = 0;j < ns2->nodeNr;j++)
4509 if (values2[j] != NULL)
4510 xmlFree(values2[j]);
4511 xmlFree(values1);
4512 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004513 xmlFree(hashs1);
4514 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004515 return(ret);
4516}
4517
William M. Brack0c022ad2002-07-12 00:56:01 +00004518static int
4519xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
4520 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00004521 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00004522 /*
4523 *At this point we are assured neither arg1 nor arg2
4524 *is a nodeset, so we can just pick the appropriate routine.
4525 */
Owen Taylor3473f882001-02-23 17:55:21 +00004526 switch (arg1->type) {
4527 case XPATH_UNDEFINED:
4528#ifdef DEBUG_EXPR
4529 xmlGenericError(xmlGenericErrorContext,
4530 "Equal: undefined\n");
4531#endif
4532 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004533 case XPATH_BOOLEAN:
4534 switch (arg2->type) {
4535 case XPATH_UNDEFINED:
4536#ifdef DEBUG_EXPR
4537 xmlGenericError(xmlGenericErrorContext,
4538 "Equal: undefined\n");
4539#endif
4540 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004541 case XPATH_BOOLEAN:
4542#ifdef DEBUG_EXPR
4543 xmlGenericError(xmlGenericErrorContext,
4544 "Equal: %d boolean %d \n",
4545 arg1->boolval, arg2->boolval);
4546#endif
4547 ret = (arg1->boolval == arg2->boolval);
4548 break;
4549 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00004550 ret = (arg1->boolval ==
4551 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004552 break;
4553 case XPATH_STRING:
4554 if ((arg2->stringval == NULL) ||
4555 (arg2->stringval[0] == 0)) ret = 0;
4556 else
4557 ret = 1;
4558 ret = (arg1->boolval == ret);
4559 break;
4560 case XPATH_USERS:
4561 case XPATH_POINT:
4562 case XPATH_RANGE:
4563 case XPATH_LOCATIONSET:
4564 TODO
4565 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004566 case XPATH_NODESET:
4567 case XPATH_XSLT_TREE:
4568 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004569 }
4570 break;
4571 case XPATH_NUMBER:
4572 switch (arg2->type) {
4573 case XPATH_UNDEFINED:
4574#ifdef DEBUG_EXPR
4575 xmlGenericError(xmlGenericErrorContext,
4576 "Equal: undefined\n");
4577#endif
4578 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004579 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00004580 ret = (arg2->boolval==
4581 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004582 break;
4583 case XPATH_STRING:
4584 valuePush(ctxt, arg2);
4585 xmlXPathNumberFunction(ctxt, 1);
4586 arg2 = valuePop(ctxt);
4587 /* no break on purpose */
4588 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004589 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004590 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4591 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004592 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4593 if (xmlXPathIsInf(arg2->floatval) == 1)
4594 ret = 1;
4595 else
4596 ret = 0;
4597 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4598 if (xmlXPathIsInf(arg2->floatval) == -1)
4599 ret = 1;
4600 else
4601 ret = 0;
4602 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4603 if (xmlXPathIsInf(arg1->floatval) == 1)
4604 ret = 1;
4605 else
4606 ret = 0;
4607 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4608 if (xmlXPathIsInf(arg1->floatval) == -1)
4609 ret = 1;
4610 else
4611 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004612 } else {
4613 ret = (arg1->floatval == arg2->floatval);
4614 }
Owen Taylor3473f882001-02-23 17:55:21 +00004615 break;
4616 case XPATH_USERS:
4617 case XPATH_POINT:
4618 case XPATH_RANGE:
4619 case XPATH_LOCATIONSET:
4620 TODO
4621 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004622 case XPATH_NODESET:
4623 case XPATH_XSLT_TREE:
4624 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004625 }
4626 break;
4627 case XPATH_STRING:
4628 switch (arg2->type) {
4629 case XPATH_UNDEFINED:
4630#ifdef DEBUG_EXPR
4631 xmlGenericError(xmlGenericErrorContext,
4632 "Equal: undefined\n");
4633#endif
4634 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004635 case XPATH_BOOLEAN:
4636 if ((arg1->stringval == NULL) ||
4637 (arg1->stringval[0] == 0)) ret = 0;
4638 else
4639 ret = 1;
4640 ret = (arg2->boolval == ret);
4641 break;
4642 case XPATH_STRING:
4643 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4644 break;
4645 case XPATH_NUMBER:
4646 valuePush(ctxt, arg1);
4647 xmlXPathNumberFunction(ctxt, 1);
4648 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004649 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004650 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4651 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004652 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4653 if (xmlXPathIsInf(arg2->floatval) == 1)
4654 ret = 1;
4655 else
4656 ret = 0;
4657 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4658 if (xmlXPathIsInf(arg2->floatval) == -1)
4659 ret = 1;
4660 else
4661 ret = 0;
4662 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4663 if (xmlXPathIsInf(arg1->floatval) == 1)
4664 ret = 1;
4665 else
4666 ret = 0;
4667 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4668 if (xmlXPathIsInf(arg1->floatval) == -1)
4669 ret = 1;
4670 else
4671 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004672 } else {
4673 ret = (arg1->floatval == arg2->floatval);
4674 }
Owen Taylor3473f882001-02-23 17:55:21 +00004675 break;
4676 case XPATH_USERS:
4677 case XPATH_POINT:
4678 case XPATH_RANGE:
4679 case XPATH_LOCATIONSET:
4680 TODO
4681 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004682 case XPATH_NODESET:
4683 case XPATH_XSLT_TREE:
4684 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004685 }
4686 break;
4687 case XPATH_USERS:
4688 case XPATH_POINT:
4689 case XPATH_RANGE:
4690 case XPATH_LOCATIONSET:
4691 TODO
4692 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004693 case XPATH_NODESET:
4694 case XPATH_XSLT_TREE:
4695 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004696 }
4697 xmlXPathFreeObject(arg1);
4698 xmlXPathFreeObject(arg2);
4699 return(ret);
4700}
4701
William M. Brack0c022ad2002-07-12 00:56:01 +00004702/**
4703 * xmlXPathEqualValues:
4704 * @ctxt: the XPath Parser context
4705 *
4706 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4707 *
4708 * Returns 0 or 1 depending on the results of the test.
4709 */
4710int
4711xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4712 xmlXPathObjectPtr arg1, arg2, argtmp;
4713 int ret = 0;
4714
4715 arg2 = valuePop(ctxt);
4716 arg1 = valuePop(ctxt);
4717 if ((arg1 == NULL) || (arg2 == NULL)) {
4718 if (arg1 != NULL)
4719 xmlXPathFreeObject(arg1);
4720 else
4721 xmlXPathFreeObject(arg2);
4722 XP_ERROR0(XPATH_INVALID_OPERAND);
4723 }
4724
4725 if (arg1 == arg2) {
4726#ifdef DEBUG_EXPR
4727 xmlGenericError(xmlGenericErrorContext,
4728 "Equal: by pointer\n");
4729#endif
4730 return(1);
4731 }
4732
4733 /*
4734 *If either argument is a nodeset, it's a 'special case'
4735 */
4736 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4737 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4738 /*
4739 *Hack it to assure arg1 is the nodeset
4740 */
4741 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4742 argtmp = arg2;
4743 arg2 = arg1;
4744 arg1 = argtmp;
4745 }
4746 switch (arg2->type) {
4747 case XPATH_UNDEFINED:
4748#ifdef DEBUG_EXPR
4749 xmlGenericError(xmlGenericErrorContext,
4750 "Equal: undefined\n");
4751#endif
4752 break;
4753 case XPATH_NODESET:
4754 case XPATH_XSLT_TREE:
4755 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
4756 break;
4757 case XPATH_BOOLEAN:
4758 if ((arg1->nodesetval == NULL) ||
4759 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4760 else
4761 ret = 1;
4762 ret = (ret == arg2->boolval);
4763 break;
4764 case XPATH_NUMBER:
4765 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
4766 break;
4767 case XPATH_STRING:
4768 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
4769 break;
4770 case XPATH_USERS:
4771 case XPATH_POINT:
4772 case XPATH_RANGE:
4773 case XPATH_LOCATIONSET:
4774 TODO
4775 break;
4776 }
4777 xmlXPathFreeObject(arg1);
4778 xmlXPathFreeObject(arg2);
4779 return(ret);
4780 }
4781
4782 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4783}
4784
4785/**
4786 * xmlXPathNotEqualValues:
4787 * @ctxt: the XPath Parser context
4788 *
4789 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4790 *
4791 * Returns 0 or 1 depending on the results of the test.
4792 */
4793int
4794xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
4795 xmlXPathObjectPtr arg1, arg2, argtmp;
4796 int ret = 0;
4797
4798 arg2 = valuePop(ctxt);
4799 arg1 = valuePop(ctxt);
4800 if ((arg1 == NULL) || (arg2 == NULL)) {
4801 if (arg1 != NULL)
4802 xmlXPathFreeObject(arg1);
4803 else
4804 xmlXPathFreeObject(arg2);
4805 XP_ERROR0(XPATH_INVALID_OPERAND);
4806 }
4807
4808 if (arg1 == arg2) {
4809#ifdef DEBUG_EXPR
4810 xmlGenericError(xmlGenericErrorContext,
4811 "NotEqual: by pointer\n");
4812#endif
4813 return(0);
4814 }
4815
4816 /*
4817 *If either argument is a nodeset, it's a 'special case'
4818 */
4819 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4820 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4821 /*
4822 *Hack it to assure arg1 is the nodeset
4823 */
4824 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4825 argtmp = arg2;
4826 arg2 = arg1;
4827 arg1 = argtmp;
4828 }
4829 switch (arg2->type) {
4830 case XPATH_UNDEFINED:
4831#ifdef DEBUG_EXPR
4832 xmlGenericError(xmlGenericErrorContext,
4833 "NotEqual: undefined\n");
4834#endif
4835 break;
4836 case XPATH_NODESET:
4837 case XPATH_XSLT_TREE:
4838 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
4839 break;
4840 case XPATH_BOOLEAN:
4841 if ((arg1->nodesetval == NULL) ||
4842 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4843 else
4844 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00004845 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00004846 break;
4847 case XPATH_NUMBER:
4848 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
4849 break;
4850 case XPATH_STRING:
4851 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
4852 break;
4853 case XPATH_USERS:
4854 case XPATH_POINT:
4855 case XPATH_RANGE:
4856 case XPATH_LOCATIONSET:
4857 TODO
4858 break;
4859 }
4860 xmlXPathFreeObject(arg1);
4861 xmlXPathFreeObject(arg2);
4862 return(ret);
4863 }
4864
4865 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4866}
Owen Taylor3473f882001-02-23 17:55:21 +00004867
4868/**
4869 * xmlXPathCompareValues:
4870 * @ctxt: the XPath Parser context
4871 * @inf: less than (1) or greater than (0)
4872 * @strict: is the comparison strict
4873 *
4874 * Implement the compare operation on XPath objects:
4875 * @arg1 < @arg2 (1, 1, ...
4876 * @arg1 <= @arg2 (1, 0, ...
4877 * @arg1 > @arg2 (0, 1, ...
4878 * @arg1 >= @arg2 (0, 0, ...
4879 *
4880 * When neither object to be compared is a node-set and the operator is
4881 * <=, <, >=, >, then the objects are compared by converted both objects
4882 * to numbers and comparing the numbers according to IEEE 754. The <
4883 * comparison will be true if and only if the first number is less than the
4884 * second number. The <= comparison will be true if and only if the first
4885 * number is less than or equal to the second number. The > comparison
4886 * will be true if and only if the first number is greater than the second
4887 * number. The >= comparison will be true if and only if the first number
4888 * is greater than or equal to the second number.
4889 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004890 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00004891 */
4892int
4893xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004894 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004895 xmlXPathObjectPtr arg1, arg2;
4896
William M. Brack0c022ad2002-07-12 00:56:01 +00004897 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00004898 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00004899 if ((arg1 == NULL) || (arg2 == NULL)) {
4900 if (arg1 != NULL)
4901 xmlXPathFreeObject(arg1);
4902 else
4903 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004904 XP_ERROR0(XPATH_INVALID_OPERAND);
4905 }
4906
William M. Brack0c022ad2002-07-12 00:56:01 +00004907 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4908 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4909 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
4910 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004911 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004912 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00004913 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004914 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
4915 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004916 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004917 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
4918 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00004919 }
4920 }
4921 return(ret);
4922 }
4923
4924 if (arg1->type != XPATH_NUMBER) {
4925 valuePush(ctxt, arg1);
4926 xmlXPathNumberFunction(ctxt, 1);
4927 arg1 = valuePop(ctxt);
4928 }
4929 if (arg1->type != XPATH_NUMBER) {
4930 xmlXPathFreeObject(arg1);
4931 xmlXPathFreeObject(arg2);
4932 XP_ERROR0(XPATH_INVALID_OPERAND);
4933 }
4934 if (arg2->type != XPATH_NUMBER) {
4935 valuePush(ctxt, arg2);
4936 xmlXPathNumberFunction(ctxt, 1);
4937 arg2 = valuePop(ctxt);
4938 }
4939 if (arg2->type != XPATH_NUMBER) {
4940 xmlXPathFreeObject(arg1);
4941 xmlXPathFreeObject(arg2);
4942 XP_ERROR0(XPATH_INVALID_OPERAND);
4943 }
4944 /*
4945 * Add tests for infinity and nan
4946 * => feedback on 3.4 for Inf and NaN
4947 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004948 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00004949 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004950 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004951 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004952 arg1i=xmlXPathIsInf(arg1->floatval);
4953 arg2i=xmlXPathIsInf(arg2->floatval);
4954 if (inf && strict) {
4955 if ((arg1i == -1 && arg2i != -1) ||
4956 (arg2i == 1 && arg1i != 1)) {
4957 ret = 1;
4958 } else if (arg1i == 0 && arg2i == 0) {
4959 ret = (arg1->floatval < arg2->floatval);
4960 } else {
4961 ret = 0;
4962 }
4963 }
4964 else if (inf && !strict) {
4965 if (arg1i == -1 || arg2i == 1) {
4966 ret = 1;
4967 } else if (arg1i == 0 && arg2i == 0) {
4968 ret = (arg1->floatval <= arg2->floatval);
4969 } else {
4970 ret = 0;
4971 }
4972 }
4973 else if (!inf && strict) {
4974 if ((arg1i == 1 && arg2i != 1) ||
4975 (arg2i == -1 && arg1i != -1)) {
4976 ret = 1;
4977 } else if (arg1i == 0 && arg2i == 0) {
4978 ret = (arg1->floatval > arg2->floatval);
4979 } else {
4980 ret = 0;
4981 }
4982 }
4983 else if (!inf && !strict) {
4984 if (arg1i == 1 || arg2i == -1) {
4985 ret = 1;
4986 } else if (arg1i == 0 && arg2i == 0) {
4987 ret = (arg1->floatval >= arg2->floatval);
4988 } else {
4989 ret = 0;
4990 }
4991 }
Daniel Veillard21458c82002-03-27 16:12:22 +00004992 }
Owen Taylor3473f882001-02-23 17:55:21 +00004993 xmlXPathFreeObject(arg1);
4994 xmlXPathFreeObject(arg2);
4995 return(ret);
4996}
4997
4998/**
4999 * xmlXPathValueFlipSign:
5000 * @ctxt: the XPath Parser context
5001 *
5002 * Implement the unary - operation on an XPath object
5003 * The numeric operators convert their operands to numbers as if
5004 * by calling the number function.
5005 */
5006void
5007xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005008 CAST_TO_NUMBER;
5009 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005010 if (xmlXPathIsNaN(ctxt->value->floatval))
5011 ctxt->value->floatval=xmlXPathNAN;
5012 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
5013 ctxt->value->floatval=xmlXPathNINF;
5014 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
5015 ctxt->value->floatval=xmlXPathPINF;
5016 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005017 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
5018 ctxt->value->floatval = xmlXPathNZERO;
5019 else
5020 ctxt->value->floatval = 0;
5021 }
5022 else
5023 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00005024}
5025
5026/**
5027 * xmlXPathAddValues:
5028 * @ctxt: the XPath Parser context
5029 *
5030 * Implement the add operation on XPath objects:
5031 * The numeric operators convert their operands to numbers as if
5032 * by calling the number function.
5033 */
5034void
5035xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
5036 xmlXPathObjectPtr arg;
5037 double val;
5038
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005039 arg = valuePop(ctxt);
5040 if (arg == NULL)
5041 XP_ERROR(XPATH_INVALID_OPERAND);
5042 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005043 xmlXPathFreeObject(arg);
5044
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005045 CAST_TO_NUMBER;
5046 CHECK_TYPE(XPATH_NUMBER);
5047 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00005048}
5049
5050/**
5051 * xmlXPathSubValues:
5052 * @ctxt: the XPath Parser context
5053 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005054 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00005055 * The numeric operators convert their operands to numbers as if
5056 * by calling the number function.
5057 */
5058void
5059xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
5060 xmlXPathObjectPtr arg;
5061 double val;
5062
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005063 arg = valuePop(ctxt);
5064 if (arg == NULL)
5065 XP_ERROR(XPATH_INVALID_OPERAND);
5066 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005067 xmlXPathFreeObject(arg);
5068
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005069 CAST_TO_NUMBER;
5070 CHECK_TYPE(XPATH_NUMBER);
5071 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005072}
5073
5074/**
5075 * xmlXPathMultValues:
5076 * @ctxt: the XPath Parser context
5077 *
5078 * Implement the multiply operation on XPath objects:
5079 * The numeric operators convert their operands to numbers as if
5080 * by calling the number function.
5081 */
5082void
5083xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
5084 xmlXPathObjectPtr arg;
5085 double val;
5086
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005087 arg = valuePop(ctxt);
5088 if (arg == NULL)
5089 XP_ERROR(XPATH_INVALID_OPERAND);
5090 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005091 xmlXPathFreeObject(arg);
5092
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005093 CAST_TO_NUMBER;
5094 CHECK_TYPE(XPATH_NUMBER);
5095 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005096}
5097
5098/**
5099 * xmlXPathDivValues:
5100 * @ctxt: the XPath Parser context
5101 *
5102 * Implement the div operation on XPath objects @arg1 / @arg2:
5103 * The numeric operators convert their operands to numbers as if
5104 * by calling the number function.
5105 */
5106void
5107xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
5108 xmlXPathObjectPtr arg;
5109 double val;
5110
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005111 arg = valuePop(ctxt);
5112 if (arg == NULL)
5113 XP_ERROR(XPATH_INVALID_OPERAND);
5114 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005115 xmlXPathFreeObject(arg);
5116
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005117 CAST_TO_NUMBER;
5118 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005119 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
5120 ctxt->value->floatval = xmlXPathNAN;
5121 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005122 if (ctxt->value->floatval == 0)
5123 ctxt->value->floatval = xmlXPathNAN;
5124 else if (ctxt->value->floatval > 0)
5125 ctxt->value->floatval = xmlXPathNINF;
5126 else if (ctxt->value->floatval < 0)
5127 ctxt->value->floatval = xmlXPathPINF;
5128 }
5129 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00005130 if (ctxt->value->floatval == 0)
5131 ctxt->value->floatval = xmlXPathNAN;
5132 else if (ctxt->value->floatval > 0)
5133 ctxt->value->floatval = xmlXPathPINF;
5134 else if (ctxt->value->floatval < 0)
5135 ctxt->value->floatval = xmlXPathNINF;
5136 } else
5137 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005138}
5139
5140/**
5141 * xmlXPathModValues:
5142 * @ctxt: the XPath Parser context
5143 *
5144 * Implement the mod operation on XPath objects: @arg1 / @arg2
5145 * The numeric operators convert their operands to numbers as if
5146 * by calling the number function.
5147 */
5148void
5149xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
5150 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005151 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00005152
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005153 arg = valuePop(ctxt);
5154 if (arg == NULL)
5155 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005156 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005157 xmlXPathFreeObject(arg);
5158
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005159 CAST_TO_NUMBER;
5160 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005161 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00005162 if (arg2 == 0)
5163 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005164 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00005165 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005166 }
Owen Taylor3473f882001-02-23 17:55:21 +00005167}
5168
5169/************************************************************************
5170 * *
5171 * The traversal functions *
5172 * *
5173 ************************************************************************/
5174
Owen Taylor3473f882001-02-23 17:55:21 +00005175/*
5176 * A traversal function enumerates nodes along an axis.
5177 * Initially it must be called with NULL, and it indicates
5178 * termination on the axis by returning NULL.
5179 */
5180typedef xmlNodePtr (*xmlXPathTraversalFunction)
5181 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
5182
5183/**
5184 * xmlXPathNextSelf:
5185 * @ctxt: the XPath Parser context
5186 * @cur: the current node in the traversal
5187 *
5188 * Traversal function for the "self" direction
5189 * The self axis contains just the context node itself
5190 *
5191 * Returns the next element following that axis
5192 */
5193xmlNodePtr
5194xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5195 if (cur == NULL)
5196 return(ctxt->context->node);
5197 return(NULL);
5198}
5199
5200/**
5201 * xmlXPathNextChild:
5202 * @ctxt: the XPath Parser context
5203 * @cur: the current node in the traversal
5204 *
5205 * Traversal function for the "child" direction
5206 * The child axis contains the children of the context node in document order.
5207 *
5208 * Returns the next element following that axis
5209 */
5210xmlNodePtr
5211xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5212 if (cur == NULL) {
5213 if (ctxt->context->node == NULL) return(NULL);
5214 switch (ctxt->context->node->type) {
5215 case XML_ELEMENT_NODE:
5216 case XML_TEXT_NODE:
5217 case XML_CDATA_SECTION_NODE:
5218 case XML_ENTITY_REF_NODE:
5219 case XML_ENTITY_NODE:
5220 case XML_PI_NODE:
5221 case XML_COMMENT_NODE:
5222 case XML_NOTATION_NODE:
5223 case XML_DTD_NODE:
5224 return(ctxt->context->node->children);
5225 case XML_DOCUMENT_NODE:
5226 case XML_DOCUMENT_TYPE_NODE:
5227 case XML_DOCUMENT_FRAG_NODE:
5228 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005229#ifdef LIBXML_DOCB_ENABLED
5230 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005231#endif
5232 return(((xmlDocPtr) ctxt->context->node)->children);
5233 case XML_ELEMENT_DECL:
5234 case XML_ATTRIBUTE_DECL:
5235 case XML_ENTITY_DECL:
5236 case XML_ATTRIBUTE_NODE:
5237 case XML_NAMESPACE_DECL:
5238 case XML_XINCLUDE_START:
5239 case XML_XINCLUDE_END:
5240 return(NULL);
5241 }
5242 return(NULL);
5243 }
5244 if ((cur->type == XML_DOCUMENT_NODE) ||
5245 (cur->type == XML_HTML_DOCUMENT_NODE))
5246 return(NULL);
5247 return(cur->next);
5248}
5249
5250/**
5251 * xmlXPathNextDescendant:
5252 * @ctxt: the XPath Parser context
5253 * @cur: the current node in the traversal
5254 *
5255 * Traversal function for the "descendant" direction
5256 * the descendant axis contains the descendants of the context node in document
5257 * order; a descendant is a child or a child of a child and so on.
5258 *
5259 * Returns the next element following that axis
5260 */
5261xmlNodePtr
5262xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5263 if (cur == NULL) {
5264 if (ctxt->context->node == NULL)
5265 return(NULL);
5266 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5267 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5268 return(NULL);
5269
5270 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5271 return(ctxt->context->doc->children);
5272 return(ctxt->context->node->children);
5273 }
5274
Daniel Veillard567e1b42001-08-01 15:53:47 +00005275 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00005276 /*
5277 * Do not descend on entities declarations
5278 */
5279 if (cur->children->type != XML_ENTITY_DECL) {
5280 cur = cur->children;
5281 /*
5282 * Skip DTDs
5283 */
5284 if (cur->type != XML_DTD_NODE)
5285 return(cur);
5286 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00005287 }
5288
5289 if (cur == ctxt->context->node) return(NULL);
5290
Daniel Veillard68e9e742002-11-16 15:35:11 +00005291 while (cur->next != NULL) {
5292 cur = cur->next;
5293 if ((cur->type != XML_ENTITY_DECL) &&
5294 (cur->type != XML_DTD_NODE))
5295 return(cur);
5296 }
Owen Taylor3473f882001-02-23 17:55:21 +00005297
5298 do {
5299 cur = cur->parent;
5300 if (cur == NULL) return(NULL);
5301 if (cur == ctxt->context->node) return(NULL);
5302 if (cur->next != NULL) {
5303 cur = cur->next;
5304 return(cur);
5305 }
5306 } while (cur != NULL);
5307 return(cur);
5308}
5309
5310/**
5311 * xmlXPathNextDescendantOrSelf:
5312 * @ctxt: the XPath Parser context
5313 * @cur: the current node in the traversal
5314 *
5315 * Traversal function for the "descendant-or-self" direction
5316 * the descendant-or-self axis contains the context node and the descendants
5317 * of the context node in document order; thus the context node is the first
5318 * node on the axis, and the first child of the context node is the second node
5319 * on the axis
5320 *
5321 * Returns the next element following that axis
5322 */
5323xmlNodePtr
5324xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5325 if (cur == NULL) {
5326 if (ctxt->context->node == NULL)
5327 return(NULL);
5328 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5329 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5330 return(NULL);
5331 return(ctxt->context->node);
5332 }
5333
5334 return(xmlXPathNextDescendant(ctxt, cur));
5335}
5336
5337/**
5338 * xmlXPathNextParent:
5339 * @ctxt: the XPath Parser context
5340 * @cur: the current node in the traversal
5341 *
5342 * Traversal function for the "parent" direction
5343 * The parent axis contains the parent of the context node, if there is one.
5344 *
5345 * Returns the next element following that axis
5346 */
5347xmlNodePtr
5348xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5349 /*
5350 * the parent of an attribute or namespace node is the element
5351 * to which the attribute or namespace node is attached
5352 * Namespace handling !!!
5353 */
5354 if (cur == NULL) {
5355 if (ctxt->context->node == NULL) return(NULL);
5356 switch (ctxt->context->node->type) {
5357 case XML_ELEMENT_NODE:
5358 case XML_TEXT_NODE:
5359 case XML_CDATA_SECTION_NODE:
5360 case XML_ENTITY_REF_NODE:
5361 case XML_ENTITY_NODE:
5362 case XML_PI_NODE:
5363 case XML_COMMENT_NODE:
5364 case XML_NOTATION_NODE:
5365 case XML_DTD_NODE:
5366 case XML_ELEMENT_DECL:
5367 case XML_ATTRIBUTE_DECL:
5368 case XML_XINCLUDE_START:
5369 case XML_XINCLUDE_END:
5370 case XML_ENTITY_DECL:
5371 if (ctxt->context->node->parent == NULL)
5372 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005373 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005374 ((ctxt->context->node->parent->name[0] == ' ') ||
5375 (xmlStrEqual(ctxt->context->node->parent->name,
5376 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005377 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005378 return(ctxt->context->node->parent);
5379 case XML_ATTRIBUTE_NODE: {
5380 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5381
5382 return(att->parent);
5383 }
5384 case XML_DOCUMENT_NODE:
5385 case XML_DOCUMENT_TYPE_NODE:
5386 case XML_DOCUMENT_FRAG_NODE:
5387 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005388#ifdef LIBXML_DOCB_ENABLED
5389 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005390#endif
5391 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005392 case XML_NAMESPACE_DECL: {
5393 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5394
5395 if ((ns->next != NULL) &&
5396 (ns->next->type != XML_NAMESPACE_DECL))
5397 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005398 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005399 }
Owen Taylor3473f882001-02-23 17:55:21 +00005400 }
5401 }
5402 return(NULL);
5403}
5404
5405/**
5406 * xmlXPathNextAncestor:
5407 * @ctxt: the XPath Parser context
5408 * @cur: the current node in the traversal
5409 *
5410 * Traversal function for the "ancestor" direction
5411 * the ancestor axis contains the ancestors of the context node; the ancestors
5412 * of the context node consist of the parent of context node and the parent's
5413 * parent and so on; the nodes are ordered in reverse document order; thus the
5414 * parent is the first node on the axis, and the parent's parent is the second
5415 * node on the axis
5416 *
5417 * Returns the next element following that axis
5418 */
5419xmlNodePtr
5420xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5421 /*
5422 * the parent of an attribute or namespace node is the element
5423 * to which the attribute or namespace node is attached
5424 * !!!!!!!!!!!!!
5425 */
5426 if (cur == NULL) {
5427 if (ctxt->context->node == NULL) return(NULL);
5428 switch (ctxt->context->node->type) {
5429 case XML_ELEMENT_NODE:
5430 case XML_TEXT_NODE:
5431 case XML_CDATA_SECTION_NODE:
5432 case XML_ENTITY_REF_NODE:
5433 case XML_ENTITY_NODE:
5434 case XML_PI_NODE:
5435 case XML_COMMENT_NODE:
5436 case XML_DTD_NODE:
5437 case XML_ELEMENT_DECL:
5438 case XML_ATTRIBUTE_DECL:
5439 case XML_ENTITY_DECL:
5440 case XML_NOTATION_NODE:
5441 case XML_XINCLUDE_START:
5442 case XML_XINCLUDE_END:
5443 if (ctxt->context->node->parent == NULL)
5444 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005445 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005446 ((ctxt->context->node->parent->name[0] == ' ') ||
5447 (xmlStrEqual(ctxt->context->node->parent->name,
5448 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005449 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005450 return(ctxt->context->node->parent);
5451 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005452 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005453
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005454 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005455 }
5456 case XML_DOCUMENT_NODE:
5457 case XML_DOCUMENT_TYPE_NODE:
5458 case XML_DOCUMENT_FRAG_NODE:
5459 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005460#ifdef LIBXML_DOCB_ENABLED
5461 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005462#endif
5463 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005464 case XML_NAMESPACE_DECL: {
5465 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5466
5467 if ((ns->next != NULL) &&
5468 (ns->next->type != XML_NAMESPACE_DECL))
5469 return((xmlNodePtr) ns->next);
5470 /* Bad, how did that namespace ended-up there ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005471 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005472 }
Owen Taylor3473f882001-02-23 17:55:21 +00005473 }
5474 return(NULL);
5475 }
5476 if (cur == ctxt->context->doc->children)
5477 return((xmlNodePtr) ctxt->context->doc);
5478 if (cur == (xmlNodePtr) ctxt->context->doc)
5479 return(NULL);
5480 switch (cur->type) {
5481 case XML_ELEMENT_NODE:
5482 case XML_TEXT_NODE:
5483 case XML_CDATA_SECTION_NODE:
5484 case XML_ENTITY_REF_NODE:
5485 case XML_ENTITY_NODE:
5486 case XML_PI_NODE:
5487 case XML_COMMENT_NODE:
5488 case XML_NOTATION_NODE:
5489 case XML_DTD_NODE:
5490 case XML_ELEMENT_DECL:
5491 case XML_ATTRIBUTE_DECL:
5492 case XML_ENTITY_DECL:
5493 case XML_XINCLUDE_START:
5494 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005495 if (cur->parent == NULL)
5496 return(NULL);
5497 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005498 ((cur->parent->name[0] == ' ') ||
5499 (xmlStrEqual(cur->parent->name,
5500 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005501 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005502 return(cur->parent);
5503 case XML_ATTRIBUTE_NODE: {
5504 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5505
5506 return(att->parent);
5507 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005508 case XML_NAMESPACE_DECL: {
5509 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5510
5511 if ((ns->next != NULL) &&
5512 (ns->next->type != XML_NAMESPACE_DECL))
5513 return((xmlNodePtr) ns->next);
5514 /* Bad, how did that namespace ended-up there ? */
5515 return(NULL);
5516 }
Owen Taylor3473f882001-02-23 17:55:21 +00005517 case XML_DOCUMENT_NODE:
5518 case XML_DOCUMENT_TYPE_NODE:
5519 case XML_DOCUMENT_FRAG_NODE:
5520 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005521#ifdef LIBXML_DOCB_ENABLED
5522 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005523#endif
5524 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005525 }
5526 return(NULL);
5527}
5528
5529/**
5530 * xmlXPathNextAncestorOrSelf:
5531 * @ctxt: the XPath Parser context
5532 * @cur: the current node in the traversal
5533 *
5534 * Traversal function for the "ancestor-or-self" direction
5535 * he ancestor-or-self axis contains the context node and ancestors of
5536 * the context node in reverse document order; thus the context node is
5537 * the first node on the axis, and the context node's parent the second;
5538 * parent here is defined the same as with the parent axis.
5539 *
5540 * Returns the next element following that axis
5541 */
5542xmlNodePtr
5543xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5544 if (cur == NULL)
5545 return(ctxt->context->node);
5546 return(xmlXPathNextAncestor(ctxt, cur));
5547}
5548
5549/**
5550 * xmlXPathNextFollowingSibling:
5551 * @ctxt: the XPath Parser context
5552 * @cur: the current node in the traversal
5553 *
5554 * Traversal function for the "following-sibling" direction
5555 * The following-sibling axis contains the following siblings of the context
5556 * node in document order.
5557 *
5558 * Returns the next element following that axis
5559 */
5560xmlNodePtr
5561xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5562 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5563 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5564 return(NULL);
5565 if (cur == (xmlNodePtr) ctxt->context->doc)
5566 return(NULL);
5567 if (cur == NULL)
5568 return(ctxt->context->node->next);
5569 return(cur->next);
5570}
5571
5572/**
5573 * xmlXPathNextPrecedingSibling:
5574 * @ctxt: the XPath Parser context
5575 * @cur: the current node in the traversal
5576 *
5577 * Traversal function for the "preceding-sibling" direction
5578 * The preceding-sibling axis contains the preceding siblings of the context
5579 * node in reverse document order; the first preceding sibling is first on the
5580 * axis; the sibling preceding that node is the second on the axis and so on.
5581 *
5582 * Returns the next element following that axis
5583 */
5584xmlNodePtr
5585xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5586 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5587 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5588 return(NULL);
5589 if (cur == (xmlNodePtr) ctxt->context->doc)
5590 return(NULL);
5591 if (cur == NULL)
5592 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005593 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5594 cur = cur->prev;
5595 if (cur == NULL)
5596 return(ctxt->context->node->prev);
5597 }
Owen Taylor3473f882001-02-23 17:55:21 +00005598 return(cur->prev);
5599}
5600
5601/**
5602 * xmlXPathNextFollowing:
5603 * @ctxt: the XPath Parser context
5604 * @cur: the current node in the traversal
5605 *
5606 * Traversal function for the "following" direction
5607 * The following axis contains all nodes in the same document as the context
5608 * node that are after the context node in document order, excluding any
5609 * descendants and excluding attribute nodes and namespace nodes; the nodes
5610 * are ordered in document order
5611 *
5612 * Returns the next element following that axis
5613 */
5614xmlNodePtr
5615xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5616 if (cur != NULL && cur->children != NULL)
5617 return cur->children ;
5618 if (cur == NULL) cur = ctxt->context->node;
5619 if (cur == NULL) return(NULL) ; /* ERROR */
5620 if (cur->next != NULL) return(cur->next) ;
5621 do {
5622 cur = cur->parent;
5623 if (cur == NULL) return(NULL);
5624 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5625 if (cur->next != NULL) return(cur->next);
5626 } while (cur != NULL);
5627 return(cur);
5628}
5629
5630/*
5631 * xmlXPathIsAncestor:
5632 * @ancestor: the ancestor node
5633 * @node: the current node
5634 *
5635 * Check that @ancestor is a @node's ancestor
5636 *
5637 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5638 */
5639static int
5640xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5641 if ((ancestor == NULL) || (node == NULL)) return(0);
5642 /* nodes need to be in the same document */
5643 if (ancestor->doc != node->doc) return(0);
5644 /* avoid searching if ancestor or node is the root node */
5645 if (ancestor == (xmlNodePtr) node->doc) return(1);
5646 if (node == (xmlNodePtr) ancestor->doc) return(0);
5647 while (node->parent != NULL) {
5648 if (node->parent == ancestor)
5649 return(1);
5650 node = node->parent;
5651 }
5652 return(0);
5653}
5654
5655/**
5656 * xmlXPathNextPreceding:
5657 * @ctxt: the XPath Parser context
5658 * @cur: the current node in the traversal
5659 *
5660 * Traversal function for the "preceding" direction
5661 * the preceding axis contains all nodes in the same document as the context
5662 * node that are before the context node in document order, excluding any
5663 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5664 * ordered in reverse document order
5665 *
5666 * Returns the next element following that axis
5667 */
5668xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005669xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5670{
Owen Taylor3473f882001-02-23 17:55:21 +00005671 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005672 cur = ctxt->context->node;
5673 if (cur == NULL)
5674 return (NULL);
5675 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5676 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005677 do {
5678 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005679 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5680 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005681 }
5682
5683 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005684 if (cur == NULL)
5685 return (NULL);
5686 if (cur == ctxt->context->doc->children)
5687 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005688 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005689 return (cur);
5690}
5691
5692/**
5693 * xmlXPathNextPrecedingInternal:
5694 * @ctxt: the XPath Parser context
5695 * @cur: the current node in the traversal
5696 *
5697 * Traversal function for the "preceding" direction
5698 * the preceding axis contains all nodes in the same document as the context
5699 * node that are before the context node in document order, excluding any
5700 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5701 * ordered in reverse document order
5702 * This is a faster implementation but internal only since it requires a
5703 * state kept in the parser context: ctxt->ancestor.
5704 *
5705 * Returns the next element following that axis
5706 */
5707static xmlNodePtr
5708xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5709 xmlNodePtr cur)
5710{
5711 if (cur == NULL) {
5712 cur = ctxt->context->node;
5713 if (cur == NULL)
5714 return (NULL);
5715 ctxt->ancestor = cur->parent;
5716 }
5717 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5718 cur = cur->prev;
5719 while (cur->prev == NULL) {
5720 cur = cur->parent;
5721 if (cur == NULL)
5722 return (NULL);
5723 if (cur == ctxt->context->doc->children)
5724 return (NULL);
5725 if (cur != ctxt->ancestor)
5726 return (cur);
5727 ctxt->ancestor = cur->parent;
5728 }
5729 cur = cur->prev;
5730 while (cur->last != NULL)
5731 cur = cur->last;
5732 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005733}
5734
5735/**
5736 * xmlXPathNextNamespace:
5737 * @ctxt: the XPath Parser context
5738 * @cur: the current attribute in the traversal
5739 *
5740 * Traversal function for the "namespace" direction
5741 * the namespace axis contains the namespace nodes of the context node;
5742 * the order of nodes on this axis is implementation-defined; the axis will
5743 * be empty unless the context node is an element
5744 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005745 * We keep the XML namespace node at the end of the list.
5746 *
Owen Taylor3473f882001-02-23 17:55:21 +00005747 * Returns the next element following that axis
5748 */
5749xmlNodePtr
5750xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5751 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00005752 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005753 if (ctxt->context->tmpNsList != NULL)
5754 xmlFree(ctxt->context->tmpNsList);
5755 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005756 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005757 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005758 if (ctxt->context->tmpNsList != NULL) {
5759 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
5760 ctxt->context->tmpNsNr++;
5761 }
5762 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005763 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005764 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00005765 if (ctxt->context->tmpNsNr > 0) {
5766 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
5767 } else {
5768 if (ctxt->context->tmpNsList != NULL)
5769 xmlFree(ctxt->context->tmpNsList);
5770 ctxt->context->tmpNsList = NULL;
5771 return(NULL);
5772 }
Owen Taylor3473f882001-02-23 17:55:21 +00005773}
5774
5775/**
5776 * xmlXPathNextAttribute:
5777 * @ctxt: the XPath Parser context
5778 * @cur: the current attribute in the traversal
5779 *
5780 * Traversal function for the "attribute" direction
5781 * TODO: support DTD inherited default attributes
5782 *
5783 * Returns the next element following that axis
5784 */
5785xmlNodePtr
5786xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005787 if (ctxt->context->node == NULL)
5788 return(NULL);
5789 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5790 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005791 if (cur == NULL) {
5792 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5793 return(NULL);
5794 return((xmlNodePtr)ctxt->context->node->properties);
5795 }
5796 return((xmlNodePtr)cur->next);
5797}
5798
5799/************************************************************************
5800 * *
5801 * NodeTest Functions *
5802 * *
5803 ************************************************************************/
5804
Owen Taylor3473f882001-02-23 17:55:21 +00005805#define IS_FUNCTION 200
5806
Owen Taylor3473f882001-02-23 17:55:21 +00005807
5808/************************************************************************
5809 * *
5810 * Implicit tree core function library *
5811 * *
5812 ************************************************************************/
5813
5814/**
5815 * xmlXPathRoot:
5816 * @ctxt: the XPath Parser context
5817 *
5818 * Initialize the context to the root of the document
5819 */
5820void
5821xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5822 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5823 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5824}
5825
5826/************************************************************************
5827 * *
5828 * The explicit core function library *
5829 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5830 * *
5831 ************************************************************************/
5832
5833
5834/**
5835 * xmlXPathLastFunction:
5836 * @ctxt: the XPath Parser context
5837 * @nargs: the number of arguments
5838 *
5839 * Implement the last() XPath function
5840 * number last()
5841 * The last function returns the number of nodes in the context node list.
5842 */
5843void
5844xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5845 CHECK_ARITY(0);
5846 if (ctxt->context->contextSize >= 0) {
5847 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5848#ifdef DEBUG_EXPR
5849 xmlGenericError(xmlGenericErrorContext,
5850 "last() : %d\n", ctxt->context->contextSize);
5851#endif
5852 } else {
5853 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5854 }
5855}
5856
5857/**
5858 * xmlXPathPositionFunction:
5859 * @ctxt: the XPath Parser context
5860 * @nargs: the number of arguments
5861 *
5862 * Implement the position() XPath function
5863 * number position()
5864 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005865 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00005866 * will be equal to last().
5867 */
5868void
5869xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5870 CHECK_ARITY(0);
5871 if (ctxt->context->proximityPosition >= 0) {
5872 valuePush(ctxt,
5873 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5874#ifdef DEBUG_EXPR
5875 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5876 ctxt->context->proximityPosition);
5877#endif
5878 } else {
5879 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5880 }
5881}
5882
5883/**
5884 * xmlXPathCountFunction:
5885 * @ctxt: the XPath Parser context
5886 * @nargs: the number of arguments
5887 *
5888 * Implement the count() XPath function
5889 * number count(node-set)
5890 */
5891void
5892xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5893 xmlXPathObjectPtr cur;
5894
5895 CHECK_ARITY(1);
5896 if ((ctxt->value == NULL) ||
5897 ((ctxt->value->type != XPATH_NODESET) &&
5898 (ctxt->value->type != XPATH_XSLT_TREE)))
5899 XP_ERROR(XPATH_INVALID_TYPE);
5900 cur = valuePop(ctxt);
5901
Daniel Veillard911f49a2001-04-07 15:39:35 +00005902 if ((cur == NULL) || (cur->nodesetval == NULL))
5903 valuePush(ctxt, xmlXPathNewFloat((double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00005904 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00005905 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00005906 } else {
5907 if ((cur->nodesetval->nodeNr != 1) ||
5908 (cur->nodesetval->nodeTab == NULL)) {
5909 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5910 } else {
5911 xmlNodePtr tmp;
5912 int i = 0;
5913
5914 tmp = cur->nodesetval->nodeTab[0];
5915 if (tmp != NULL) {
5916 tmp = tmp->children;
5917 while (tmp != NULL) {
5918 tmp = tmp->next;
5919 i++;
5920 }
5921 }
5922 valuePush(ctxt, xmlXPathNewFloat((double) i));
5923 }
5924 }
Owen Taylor3473f882001-02-23 17:55:21 +00005925 xmlXPathFreeObject(cur);
5926}
5927
5928/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005929 * xmlXPathGetElementsByIds:
5930 * @doc: the document
5931 * @ids: a whitespace separated list of IDs
5932 *
5933 * Selects elements by their unique ID.
5934 *
5935 * Returns a node-set of selected elements.
5936 */
5937static xmlNodeSetPtr
5938xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5939 xmlNodeSetPtr ret;
5940 const xmlChar *cur = ids;
5941 xmlChar *ID;
5942 xmlAttrPtr attr;
5943 xmlNodePtr elem = NULL;
5944
Daniel Veillard7a985a12003-07-06 17:57:42 +00005945 if (ids == NULL) return(NULL);
5946
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005947 ret = xmlXPathNodeSetCreate(NULL);
5948
5949 while (IS_BLANK(*cur)) cur++;
5950 while (*cur != 0) {
Daniel Veillarde209b332003-03-26 21:40:13 +00005951 while ((!IS_BLANK(*cur)) && (*cur != 0))
5952 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005953
5954 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00005955 if (ID != NULL) {
5956 if (xmlValidateNCName(ID, 1) == 0) {
5957 attr = xmlGetID(doc, ID);
5958 if (attr != NULL) {
5959 if (attr->type == XML_ATTRIBUTE_NODE)
5960 elem = attr->parent;
5961 else if (attr->type == XML_ELEMENT_NODE)
5962 elem = (xmlNodePtr) attr;
5963 else
5964 elem = NULL;
5965 if (elem != NULL)
5966 xmlXPathNodeSetAdd(ret, elem);
5967 }
5968 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005969 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00005970 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005971
5972 while (IS_BLANK(*cur)) cur++;
5973 ids = cur;
5974 }
5975 return(ret);
5976}
5977
5978/**
Owen Taylor3473f882001-02-23 17:55:21 +00005979 * xmlXPathIdFunction:
5980 * @ctxt: the XPath Parser context
5981 * @nargs: the number of arguments
5982 *
5983 * Implement the id() XPath function
5984 * node-set id(object)
5985 * The id function selects elements by their unique ID
5986 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
5987 * then the result is the union of the result of applying id to the
5988 * string value of each of the nodes in the argument node-set. When the
5989 * argument to id is of any other type, the argument is converted to a
5990 * string as if by a call to the string function; the string is split
5991 * into a whitespace-separated list of tokens (whitespace is any sequence
5992 * of characters matching the production S); the result is a node-set
5993 * containing the elements in the same document as the context node that
5994 * have a unique ID equal to any of the tokens in the list.
5995 */
5996void
5997xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005998 xmlChar *tokens;
5999 xmlNodeSetPtr ret;
6000 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00006001
6002 CHECK_ARITY(1);
6003 obj = valuePop(ctxt);
6004 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00006005 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006006 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00006007 int i;
6008
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006009 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006010
Daniel Veillard911f49a2001-04-07 15:39:35 +00006011 if (obj->nodesetval != NULL) {
6012 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006013 tokens =
6014 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
6015 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
6016 ret = xmlXPathNodeSetMerge(ret, ns);
6017 xmlXPathFreeNodeSet(ns);
6018 if (tokens != NULL)
6019 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006020 }
Owen Taylor3473f882001-02-23 17:55:21 +00006021 }
6022
6023 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006024 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006025 return;
6026 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006027 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00006028
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006029 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
6030 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006031
Owen Taylor3473f882001-02-23 17:55:21 +00006032 xmlXPathFreeObject(obj);
6033 return;
6034}
6035
6036/**
6037 * xmlXPathLocalNameFunction:
6038 * @ctxt: the XPath Parser context
6039 * @nargs: the number of arguments
6040 *
6041 * Implement the local-name() XPath function
6042 * string local-name(node-set?)
6043 * The local-name function returns a string containing the local part
6044 * of the name of the node in the argument node-set that is first in
6045 * document order. If the node-set is empty or the first node has no
6046 * name, an empty string is returned. If the argument is omitted it
6047 * defaults to the context node.
6048 */
6049void
6050xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6051 xmlXPathObjectPtr cur;
6052
6053 if (nargs == 0) {
6054 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6055 nargs = 1;
6056 }
6057
6058 CHECK_ARITY(1);
6059 if ((ctxt->value == NULL) ||
6060 ((ctxt->value->type != XPATH_NODESET) &&
6061 (ctxt->value->type != XPATH_XSLT_TREE)))
6062 XP_ERROR(XPATH_INVALID_TYPE);
6063 cur = valuePop(ctxt);
6064
Daniel Veillard911f49a2001-04-07 15:39:35 +00006065 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006066 valuePush(ctxt, xmlXPathNewCString(""));
6067 } else {
6068 int i = 0; /* Should be first in document order !!!!! */
6069 switch (cur->nodesetval->nodeTab[i]->type) {
6070 case XML_ELEMENT_NODE:
6071 case XML_ATTRIBUTE_NODE:
6072 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006073 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6074 valuePush(ctxt, xmlXPathNewCString(""));
6075 else
6076 valuePush(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006077 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
6078 break;
6079 case XML_NAMESPACE_DECL:
6080 valuePush(ctxt, xmlXPathNewString(
6081 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
6082 break;
6083 default:
6084 valuePush(ctxt, xmlXPathNewCString(""));
6085 }
6086 }
6087 xmlXPathFreeObject(cur);
6088}
6089
6090/**
6091 * xmlXPathNamespaceURIFunction:
6092 * @ctxt: the XPath Parser context
6093 * @nargs: the number of arguments
6094 *
6095 * Implement the namespace-uri() XPath function
6096 * string namespace-uri(node-set?)
6097 * The namespace-uri function returns a string containing the
6098 * namespace URI of the expanded name of the node in the argument
6099 * node-set that is first in document order. If the node-set is empty,
6100 * the first node has no name, or the expanded name has no namespace
6101 * URI, an empty string is returned. If the argument is omitted it
6102 * defaults to the context node.
6103 */
6104void
6105xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6106 xmlXPathObjectPtr cur;
6107
6108 if (nargs == 0) {
6109 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6110 nargs = 1;
6111 }
6112 CHECK_ARITY(1);
6113 if ((ctxt->value == NULL) ||
6114 ((ctxt->value->type != XPATH_NODESET) &&
6115 (ctxt->value->type != XPATH_XSLT_TREE)))
6116 XP_ERROR(XPATH_INVALID_TYPE);
6117 cur = valuePop(ctxt);
6118
Daniel Veillard911f49a2001-04-07 15:39:35 +00006119 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006120 valuePush(ctxt, xmlXPathNewCString(""));
6121 } else {
6122 int i = 0; /* Should be first in document order !!!!! */
6123 switch (cur->nodesetval->nodeTab[i]->type) {
6124 case XML_ELEMENT_NODE:
6125 case XML_ATTRIBUTE_NODE:
6126 if (cur->nodesetval->nodeTab[i]->ns == NULL)
6127 valuePush(ctxt, xmlXPathNewCString(""));
6128 else
6129 valuePush(ctxt, xmlXPathNewString(
6130 cur->nodesetval->nodeTab[i]->ns->href));
6131 break;
6132 default:
6133 valuePush(ctxt, xmlXPathNewCString(""));
6134 }
6135 }
6136 xmlXPathFreeObject(cur);
6137}
6138
6139/**
6140 * xmlXPathNameFunction:
6141 * @ctxt: the XPath Parser context
6142 * @nargs: the number of arguments
6143 *
6144 * Implement the name() XPath function
6145 * string name(node-set?)
6146 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006147 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00006148 * order. The QName must represent the name with respect to the namespace
6149 * declarations in effect on the node whose name is being represented.
6150 * Typically, this will be the form in which the name occurred in the XML
6151 * source. This need not be the case if there are namespace declarations
6152 * in effect on the node that associate multiple prefixes with the same
6153 * namespace. However, an implementation may include information about
6154 * the original prefix in its representation of nodes; in this case, an
6155 * implementation can ensure that the returned string is always the same
6156 * as the QName used in the XML source. If the argument it omitted it
6157 * defaults to the context node.
6158 * Libxml keep the original prefix so the "real qualified name" used is
6159 * returned.
6160 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006161static void
Daniel Veillard04383752001-07-08 14:27:15 +00006162xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
6163{
Owen Taylor3473f882001-02-23 17:55:21 +00006164 xmlXPathObjectPtr cur;
6165
6166 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00006167 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6168 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006169 }
6170
6171 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00006172 if ((ctxt->value == NULL) ||
6173 ((ctxt->value->type != XPATH_NODESET) &&
6174 (ctxt->value->type != XPATH_XSLT_TREE)))
6175 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006176 cur = valuePop(ctxt);
6177
Daniel Veillard911f49a2001-04-07 15:39:35 +00006178 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006179 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00006180 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006181 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00006182
Daniel Veillard04383752001-07-08 14:27:15 +00006183 switch (cur->nodesetval->nodeTab[i]->type) {
6184 case XML_ELEMENT_NODE:
6185 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006186 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6187 valuePush(ctxt, xmlXPathNewCString(""));
6188 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6189 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006190 valuePush(ctxt,
Daniel Veillardc00cda82003-04-07 10:22:39 +00006191 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
Daniel Veillard04383752001-07-08 14:27:15 +00006192
Daniel Veillard652d8a92003-02-04 19:28:49 +00006193 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006194 xmlChar *fullname;
6195
6196 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
6197 cur->nodesetval->nodeTab[i]->ns->prefix,
6198 NULL, 0);
6199 if (fullname == cur->nodesetval->nodeTab[i]->name)
6200 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
6201 if (fullname == NULL) {
6202 XP_ERROR(XPATH_MEMORY_ERROR);
6203 }
6204 valuePush(ctxt, xmlXPathWrapString(fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00006205 }
6206 break;
6207 default:
6208 valuePush(ctxt,
6209 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6210 xmlXPathLocalNameFunction(ctxt, 1);
6211 }
Owen Taylor3473f882001-02-23 17:55:21 +00006212 }
6213 xmlXPathFreeObject(cur);
6214}
6215
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006216
6217/**
Owen Taylor3473f882001-02-23 17:55:21 +00006218 * xmlXPathStringFunction:
6219 * @ctxt: the XPath Parser context
6220 * @nargs: the number of arguments
6221 *
6222 * Implement the string() XPath function
6223 * string string(object?)
6224 * he string function converts an object to a string as follows:
6225 * - A node-set is converted to a string by returning the value of
6226 * the node in the node-set that is first in document order.
6227 * If the node-set is empty, an empty string is returned.
6228 * - A number is converted to a string as follows
6229 * + NaN is converted to the string NaN
6230 * + positive zero is converted to the string 0
6231 * + negative zero is converted to the string 0
6232 * + positive infinity is converted to the string Infinity
6233 * + negative infinity is converted to the string -Infinity
6234 * + if the number is an integer, the number is represented in
6235 * decimal form as a Number with no decimal point and no leading
6236 * zeros, preceded by a minus sign (-) if the number is negative
6237 * + otherwise, the number is represented in decimal form as a
6238 * Number including a decimal point with at least one digit
6239 * before the decimal point and at least one digit after the
6240 * decimal point, preceded by a minus sign (-) if the number
6241 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006242 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00006243 * before the decimal point; beyond the one required digit
6244 * after the decimal point there must be as many, but only as
6245 * many, more digits as are needed to uniquely distinguish the
6246 * number from all other IEEE 754 numeric values.
6247 * - The boolean false value is converted to the string false.
6248 * The boolean true value is converted to the string true.
6249 *
6250 * If the argument is omitted, it defaults to a node-set with the
6251 * context node as its only member.
6252 */
6253void
6254xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6255 xmlXPathObjectPtr cur;
6256
6257 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006258 valuePush(ctxt,
6259 xmlXPathWrapString(
6260 xmlXPathCastNodeToString(ctxt->context->node)));
6261 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006262 }
6263
6264 CHECK_ARITY(1);
6265 cur = valuePop(ctxt);
6266 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006267 cur = xmlXPathConvertString(cur);
6268 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006269}
6270
6271/**
6272 * xmlXPathStringLengthFunction:
6273 * @ctxt: the XPath Parser context
6274 * @nargs: the number of arguments
6275 *
6276 * Implement the string-length() XPath function
6277 * number string-length(string?)
6278 * The string-length returns the number of characters in the string
6279 * (see [3.6 Strings]). If the argument is omitted, it defaults to
6280 * the context node converted to a string, in other words the value
6281 * of the context node.
6282 */
6283void
6284xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6285 xmlXPathObjectPtr cur;
6286
6287 if (nargs == 0) {
6288 if (ctxt->context->node == NULL) {
6289 valuePush(ctxt, xmlXPathNewFloat(0));
6290 } else {
6291 xmlChar *content;
6292
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006293 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006294 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00006295 xmlFree(content);
6296 }
6297 return;
6298 }
6299 CHECK_ARITY(1);
6300 CAST_TO_STRING;
6301 CHECK_TYPE(XPATH_STRING);
6302 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006303 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00006304 xmlXPathFreeObject(cur);
6305}
6306
6307/**
6308 * xmlXPathConcatFunction:
6309 * @ctxt: the XPath Parser context
6310 * @nargs: the number of arguments
6311 *
6312 * Implement the concat() XPath function
6313 * string concat(string, string, string*)
6314 * The concat function returns the concatenation of its arguments.
6315 */
6316void
6317xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6318 xmlXPathObjectPtr cur, newobj;
6319 xmlChar *tmp;
6320
6321 if (nargs < 2) {
6322 CHECK_ARITY(2);
6323 }
6324
6325 CAST_TO_STRING;
6326 cur = valuePop(ctxt);
6327 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6328 xmlXPathFreeObject(cur);
6329 return;
6330 }
6331 nargs--;
6332
6333 while (nargs > 0) {
6334 CAST_TO_STRING;
6335 newobj = valuePop(ctxt);
6336 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6337 xmlXPathFreeObject(newobj);
6338 xmlXPathFreeObject(cur);
6339 XP_ERROR(XPATH_INVALID_TYPE);
6340 }
6341 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6342 newobj->stringval = cur->stringval;
6343 cur->stringval = tmp;
6344
6345 xmlXPathFreeObject(newobj);
6346 nargs--;
6347 }
6348 valuePush(ctxt, cur);
6349}
6350
6351/**
6352 * xmlXPathContainsFunction:
6353 * @ctxt: the XPath Parser context
6354 * @nargs: the number of arguments
6355 *
6356 * Implement the contains() XPath function
6357 * boolean contains(string, string)
6358 * The contains function returns true if the first argument string
6359 * contains the second argument string, and otherwise returns false.
6360 */
6361void
6362xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6363 xmlXPathObjectPtr hay, needle;
6364
6365 CHECK_ARITY(2);
6366 CAST_TO_STRING;
6367 CHECK_TYPE(XPATH_STRING);
6368 needle = valuePop(ctxt);
6369 CAST_TO_STRING;
6370 hay = valuePop(ctxt);
6371 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6372 xmlXPathFreeObject(hay);
6373 xmlXPathFreeObject(needle);
6374 XP_ERROR(XPATH_INVALID_TYPE);
6375 }
6376 if (xmlStrstr(hay->stringval, needle->stringval))
6377 valuePush(ctxt, xmlXPathNewBoolean(1));
6378 else
6379 valuePush(ctxt, xmlXPathNewBoolean(0));
6380 xmlXPathFreeObject(hay);
6381 xmlXPathFreeObject(needle);
6382}
6383
6384/**
6385 * xmlXPathStartsWithFunction:
6386 * @ctxt: the XPath Parser context
6387 * @nargs: the number of arguments
6388 *
6389 * Implement the starts-with() XPath function
6390 * boolean starts-with(string, string)
6391 * The starts-with function returns true if the first argument string
6392 * starts with the second argument string, and otherwise returns false.
6393 */
6394void
6395xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6396 xmlXPathObjectPtr hay, needle;
6397 int n;
6398
6399 CHECK_ARITY(2);
6400 CAST_TO_STRING;
6401 CHECK_TYPE(XPATH_STRING);
6402 needle = valuePop(ctxt);
6403 CAST_TO_STRING;
6404 hay = valuePop(ctxt);
6405 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6406 xmlXPathFreeObject(hay);
6407 xmlXPathFreeObject(needle);
6408 XP_ERROR(XPATH_INVALID_TYPE);
6409 }
6410 n = xmlStrlen(needle->stringval);
6411 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6412 valuePush(ctxt, xmlXPathNewBoolean(0));
6413 else
6414 valuePush(ctxt, xmlXPathNewBoolean(1));
6415 xmlXPathFreeObject(hay);
6416 xmlXPathFreeObject(needle);
6417}
6418
6419/**
6420 * xmlXPathSubstringFunction:
6421 * @ctxt: the XPath Parser context
6422 * @nargs: the number of arguments
6423 *
6424 * Implement the substring() XPath function
6425 * string substring(string, number, number?)
6426 * The substring function returns the substring of the first argument
6427 * starting at the position specified in the second argument with
6428 * length specified in the third argument. For example,
6429 * substring("12345",2,3) returns "234". If the third argument is not
6430 * specified, it returns the substring starting at the position specified
6431 * in the second argument and continuing to the end of the string. For
6432 * example, substring("12345",2) returns "2345". More precisely, each
6433 * character in the string (see [3.6 Strings]) is considered to have a
6434 * numeric position: the position of the first character is 1, the position
6435 * of the second character is 2 and so on. The returned substring contains
6436 * those characters for which the position of the character is greater than
6437 * or equal to the second argument and, if the third argument is specified,
6438 * less than the sum of the second and third arguments; the comparisons
6439 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6440 * - substring("12345", 1.5, 2.6) returns "234"
6441 * - substring("12345", 0, 3) returns "12"
6442 * - substring("12345", 0 div 0, 3) returns ""
6443 * - substring("12345", 1, 0 div 0) returns ""
6444 * - substring("12345", -42, 1 div 0) returns "12345"
6445 * - substring("12345", -1 div 0, 1 div 0) returns ""
6446 */
6447void
6448xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6449 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006450 double le=0, in;
6451 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006452 xmlChar *ret;
6453
Owen Taylor3473f882001-02-23 17:55:21 +00006454 if (nargs < 2) {
6455 CHECK_ARITY(2);
6456 }
6457 if (nargs > 3) {
6458 CHECK_ARITY(3);
6459 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006460 /*
6461 * take care of possible last (position) argument
6462 */
Owen Taylor3473f882001-02-23 17:55:21 +00006463 if (nargs == 3) {
6464 CAST_TO_NUMBER;
6465 CHECK_TYPE(XPATH_NUMBER);
6466 len = valuePop(ctxt);
6467 le = len->floatval;
6468 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006469 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006470
Owen Taylor3473f882001-02-23 17:55:21 +00006471 CAST_TO_NUMBER;
6472 CHECK_TYPE(XPATH_NUMBER);
6473 start = valuePop(ctxt);
6474 in = start->floatval;
6475 xmlXPathFreeObject(start);
6476 CAST_TO_STRING;
6477 CHECK_TYPE(XPATH_STRING);
6478 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006479 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006480
Daniel Veillard97ac1312001-05-30 19:14:17 +00006481 /*
6482 * If last pos not present, calculate last position
6483 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006484 if (nargs != 3) {
6485 le = (double)m;
6486 if (in < 1.0)
6487 in = 1.0;
6488 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006489
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006490 /* Need to check for the special cases where either
6491 * the index is NaN, the length is NaN, or both
6492 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00006493 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006494 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006495 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00006496 * To meet the requirements of the spec, the arguments
6497 * must be converted to integer format before
6498 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006499 *
Daniel Veillard9e412302002-06-10 15:59:44 +00006500 * First we go to integer form, rounding up
6501 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006502 */
6503 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00006504 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00006505
Daniel Veillard9e412302002-06-10 15:59:44 +00006506 if (xmlXPathIsInf(le) == 1) {
6507 l = m;
6508 if (i < 1)
6509 i = 1;
6510 }
6511 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
6512 l = 0;
6513 else {
6514 l = (int) le;
6515 if (((double)l)+0.5 <= le) l++;
6516 }
6517
6518 /* Now we normalize inidices */
6519 i -= 1;
6520 l += i;
6521 if (i < 0)
6522 i = 0;
6523 if (l > m)
6524 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00006525
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006526 /* number of chars to copy */
6527 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00006528
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006529 ret = xmlUTF8Strsub(str->stringval, i, l);
6530 }
6531 else {
6532 ret = NULL;
6533 }
6534
Owen Taylor3473f882001-02-23 17:55:21 +00006535 if (ret == NULL)
6536 valuePush(ctxt, xmlXPathNewCString(""));
6537 else {
6538 valuePush(ctxt, xmlXPathNewString(ret));
6539 xmlFree(ret);
6540 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006541
Owen Taylor3473f882001-02-23 17:55:21 +00006542 xmlXPathFreeObject(str);
6543}
6544
6545/**
6546 * xmlXPathSubstringBeforeFunction:
6547 * @ctxt: the XPath Parser context
6548 * @nargs: the number of arguments
6549 *
6550 * Implement the substring-before() XPath function
6551 * string substring-before(string, string)
6552 * The substring-before function returns the substring of the first
6553 * argument string that precedes the first occurrence of the second
6554 * argument string in the first argument string, or the empty string
6555 * if the first argument string does not contain the second argument
6556 * string. For example, substring-before("1999/04/01","/") returns 1999.
6557 */
6558void
6559xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6560 xmlXPathObjectPtr str;
6561 xmlXPathObjectPtr find;
6562 xmlBufferPtr target;
6563 const xmlChar *point;
6564 int offset;
6565
6566 CHECK_ARITY(2);
6567 CAST_TO_STRING;
6568 find = valuePop(ctxt);
6569 CAST_TO_STRING;
6570 str = valuePop(ctxt);
6571
6572 target = xmlBufferCreate();
6573 if (target) {
6574 point = xmlStrstr(str->stringval, find->stringval);
6575 if (point) {
6576 offset = (int)(point - str->stringval);
6577 xmlBufferAdd(target, str->stringval, offset);
6578 }
6579 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6580 xmlBufferFree(target);
6581 }
6582
6583 xmlXPathFreeObject(str);
6584 xmlXPathFreeObject(find);
6585}
6586
6587/**
6588 * xmlXPathSubstringAfterFunction:
6589 * @ctxt: the XPath Parser context
6590 * @nargs: the number of arguments
6591 *
6592 * Implement the substring-after() XPath function
6593 * string substring-after(string, string)
6594 * The substring-after function returns the substring of the first
6595 * argument string that follows the first occurrence of the second
6596 * argument string in the first argument string, or the empty stringi
6597 * if the first argument string does not contain the second argument
6598 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6599 * and substring-after("1999/04/01","19") returns 99/04/01.
6600 */
6601void
6602xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6603 xmlXPathObjectPtr str;
6604 xmlXPathObjectPtr find;
6605 xmlBufferPtr target;
6606 const xmlChar *point;
6607 int offset;
6608
6609 CHECK_ARITY(2);
6610 CAST_TO_STRING;
6611 find = valuePop(ctxt);
6612 CAST_TO_STRING;
6613 str = valuePop(ctxt);
6614
6615 target = xmlBufferCreate();
6616 if (target) {
6617 point = xmlStrstr(str->stringval, find->stringval);
6618 if (point) {
6619 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6620 xmlBufferAdd(target, &str->stringval[offset],
6621 xmlStrlen(str->stringval) - offset);
6622 }
6623 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6624 xmlBufferFree(target);
6625 }
6626
6627 xmlXPathFreeObject(str);
6628 xmlXPathFreeObject(find);
6629}
6630
6631/**
6632 * xmlXPathNormalizeFunction:
6633 * @ctxt: the XPath Parser context
6634 * @nargs: the number of arguments
6635 *
6636 * Implement the normalize-space() XPath function
6637 * string normalize-space(string?)
6638 * The normalize-space function returns the argument string with white
6639 * space normalized by stripping leading and trailing whitespace
6640 * and replacing sequences of whitespace characters by a single
6641 * space. Whitespace characters are the same allowed by the S production
6642 * in XML. If the argument is omitted, it defaults to the context
6643 * node converted to a string, in other words the value of the context node.
6644 */
6645void
6646xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6647 xmlXPathObjectPtr obj = NULL;
6648 xmlChar *source = NULL;
6649 xmlBufferPtr target;
6650 xmlChar blank;
6651
6652 if (nargs == 0) {
6653 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006654 valuePush(ctxt,
6655 xmlXPathWrapString(
6656 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006657 nargs = 1;
6658 }
6659
6660 CHECK_ARITY(1);
6661 CAST_TO_STRING;
6662 CHECK_TYPE(XPATH_STRING);
6663 obj = valuePop(ctxt);
6664 source = obj->stringval;
6665
6666 target = xmlBufferCreate();
6667 if (target && source) {
6668
6669 /* Skip leading whitespaces */
6670 while (IS_BLANK(*source))
6671 source++;
6672
6673 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6674 blank = 0;
6675 while (*source) {
6676 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006677 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006678 } else {
6679 if (blank) {
6680 xmlBufferAdd(target, &blank, 1);
6681 blank = 0;
6682 }
6683 xmlBufferAdd(target, source, 1);
6684 }
6685 source++;
6686 }
6687
6688 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6689 xmlBufferFree(target);
6690 }
6691 xmlXPathFreeObject(obj);
6692}
6693
6694/**
6695 * xmlXPathTranslateFunction:
6696 * @ctxt: the XPath Parser context
6697 * @nargs: the number of arguments
6698 *
6699 * Implement the translate() XPath function
6700 * string translate(string, string, string)
6701 * The translate function returns the first argument string with
6702 * occurrences of characters in the second argument string replaced
6703 * by the character at the corresponding position in the third argument
6704 * string. For example, translate("bar","abc","ABC") returns the string
6705 * BAr. If there is a character in the second argument string with no
6706 * character at a corresponding position in the third argument string
6707 * (because the second argument string is longer than the third argument
6708 * string), then occurrences of that character in the first argument
6709 * string are removed. For example, translate("--aaa--","abc-","ABC")
6710 * returns "AAA". If a character occurs more than once in second
6711 * argument string, then the first occurrence determines the replacement
6712 * character. If the third argument string is longer than the second
6713 * argument string, then excess characters are ignored.
6714 */
6715void
6716xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006717 xmlXPathObjectPtr str;
6718 xmlXPathObjectPtr from;
6719 xmlXPathObjectPtr to;
6720 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006721 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006722 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006723 xmlChar *point;
6724 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006725
Daniel Veillarde043ee12001-04-16 14:08:07 +00006726 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006727
Daniel Veillarde043ee12001-04-16 14:08:07 +00006728 CAST_TO_STRING;
6729 to = valuePop(ctxt);
6730 CAST_TO_STRING;
6731 from = valuePop(ctxt);
6732 CAST_TO_STRING;
6733 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006734
Daniel Veillarde043ee12001-04-16 14:08:07 +00006735 target = xmlBufferCreate();
6736 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006737 max = xmlUTF8Strlen(to->stringval);
6738 for (cptr = str->stringval; (ch=*cptr); ) {
6739 offset = xmlUTF8Strloc(from->stringval, cptr);
6740 if (offset >= 0) {
6741 if (offset < max) {
6742 point = xmlUTF8Strpos(to->stringval, offset);
6743 if (point)
6744 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6745 }
6746 } else
6747 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6748
6749 /* Step to next character in input */
6750 cptr++;
6751 if ( ch & 0x80 ) {
6752 /* if not simple ascii, verify proper format */
6753 if ( (ch & 0xc0) != 0xc0 ) {
6754 xmlGenericError(xmlGenericErrorContext,
6755 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6756 break;
6757 }
6758 /* then skip over remaining bytes for this char */
6759 while ( (ch <<= 1) & 0x80 )
6760 if ( (*cptr++ & 0xc0) != 0x80 ) {
6761 xmlGenericError(xmlGenericErrorContext,
6762 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6763 break;
6764 }
6765 if (ch & 0x80) /* must have had error encountered */
6766 break;
6767 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006768 }
Owen Taylor3473f882001-02-23 17:55:21 +00006769 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006770 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6771 xmlBufferFree(target);
6772 xmlXPathFreeObject(str);
6773 xmlXPathFreeObject(from);
6774 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006775}
6776
6777/**
6778 * xmlXPathBooleanFunction:
6779 * @ctxt: the XPath Parser context
6780 * @nargs: the number of arguments
6781 *
6782 * Implement the boolean() XPath function
6783 * boolean boolean(object)
6784 * he boolean function converts its argument to a boolean as follows:
6785 * - a number is true if and only if it is neither positive or
6786 * negative zero nor NaN
6787 * - a node-set is true if and only if it is non-empty
6788 * - a string is true if and only if its length is non-zero
6789 */
6790void
6791xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6792 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006793
6794 CHECK_ARITY(1);
6795 cur = valuePop(ctxt);
6796 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006797 cur = xmlXPathConvertBoolean(cur);
6798 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006799}
6800
6801/**
6802 * xmlXPathNotFunction:
6803 * @ctxt: the XPath Parser context
6804 * @nargs: the number of arguments
6805 *
6806 * Implement the not() XPath function
6807 * boolean not(boolean)
6808 * The not function returns true if its argument is false,
6809 * and false otherwise.
6810 */
6811void
6812xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6813 CHECK_ARITY(1);
6814 CAST_TO_BOOLEAN;
6815 CHECK_TYPE(XPATH_BOOLEAN);
6816 ctxt->value->boolval = ! ctxt->value->boolval;
6817}
6818
6819/**
6820 * xmlXPathTrueFunction:
6821 * @ctxt: the XPath Parser context
6822 * @nargs: the number of arguments
6823 *
6824 * Implement the true() XPath function
6825 * boolean true()
6826 */
6827void
6828xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6829 CHECK_ARITY(0);
6830 valuePush(ctxt, xmlXPathNewBoolean(1));
6831}
6832
6833/**
6834 * xmlXPathFalseFunction:
6835 * @ctxt: the XPath Parser context
6836 * @nargs: the number of arguments
6837 *
6838 * Implement the false() XPath function
6839 * boolean false()
6840 */
6841void
6842xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6843 CHECK_ARITY(0);
6844 valuePush(ctxt, xmlXPathNewBoolean(0));
6845}
6846
6847/**
6848 * xmlXPathLangFunction:
6849 * @ctxt: the XPath Parser context
6850 * @nargs: the number of arguments
6851 *
6852 * Implement the lang() XPath function
6853 * boolean lang(string)
6854 * The lang function returns true or false depending on whether the
6855 * language of the context node as specified by xml:lang attributes
6856 * is the same as or is a sublanguage of the language specified by
6857 * the argument string. The language of the context node is determined
6858 * by the value of the xml:lang attribute on the context node, or, if
6859 * the context node has no xml:lang attribute, by the value of the
6860 * xml:lang attribute on the nearest ancestor of the context node that
6861 * has an xml:lang attribute. If there is no such attribute, then lang
6862 * returns false. If there is such an attribute, then lang returns
6863 * true if the attribute value is equal to the argument ignoring case,
6864 * or if there is some suffix starting with - such that the attribute
6865 * value is equal to the argument ignoring that suffix of the attribute
6866 * value and ignoring case.
6867 */
6868void
6869xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6870 xmlXPathObjectPtr val;
6871 const xmlChar *theLang;
6872 const xmlChar *lang;
6873 int ret = 0;
6874 int i;
6875
6876 CHECK_ARITY(1);
6877 CAST_TO_STRING;
6878 CHECK_TYPE(XPATH_STRING);
6879 val = valuePop(ctxt);
6880 lang = val->stringval;
6881 theLang = xmlNodeGetLang(ctxt->context->node);
6882 if ((theLang != NULL) && (lang != NULL)) {
6883 for (i = 0;lang[i] != 0;i++)
6884 if (toupper(lang[i]) != toupper(theLang[i]))
6885 goto not_equal;
6886 ret = 1;
6887 }
6888not_equal:
6889 xmlXPathFreeObject(val);
6890 valuePush(ctxt, xmlXPathNewBoolean(ret));
6891}
6892
6893/**
6894 * xmlXPathNumberFunction:
6895 * @ctxt: the XPath Parser context
6896 * @nargs: the number of arguments
6897 *
6898 * Implement the number() XPath function
6899 * number number(object?)
6900 */
6901void
6902xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6903 xmlXPathObjectPtr cur;
6904 double res;
6905
6906 if (nargs == 0) {
6907 if (ctxt->context->node == NULL) {
6908 valuePush(ctxt, xmlXPathNewFloat(0.0));
6909 } else {
6910 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6911
6912 res = xmlXPathStringEvalNumber(content);
6913 valuePush(ctxt, xmlXPathNewFloat(res));
6914 xmlFree(content);
6915 }
6916 return;
6917 }
6918
6919 CHECK_ARITY(1);
6920 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006921 cur = xmlXPathConvertNumber(cur);
6922 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006923}
6924
6925/**
6926 * xmlXPathSumFunction:
6927 * @ctxt: the XPath Parser context
6928 * @nargs: the number of arguments
6929 *
6930 * Implement the sum() XPath function
6931 * number sum(node-set)
6932 * The sum function returns the sum of the values of the nodes in
6933 * the argument node-set.
6934 */
6935void
6936xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6937 xmlXPathObjectPtr cur;
6938 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006939 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00006940
6941 CHECK_ARITY(1);
6942 if ((ctxt->value == NULL) ||
6943 ((ctxt->value->type != XPATH_NODESET) &&
6944 (ctxt->value->type != XPATH_XSLT_TREE)))
6945 XP_ERROR(XPATH_INVALID_TYPE);
6946 cur = valuePop(ctxt);
6947
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006948 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006949 valuePush(ctxt, xmlXPathNewFloat(0.0));
6950 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006951 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
6952 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006953 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006954 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00006955 }
6956 xmlXPathFreeObject(cur);
6957}
6958
6959/**
6960 * xmlXPathFloorFunction:
6961 * @ctxt: the XPath Parser context
6962 * @nargs: the number of arguments
6963 *
6964 * Implement the floor() XPath function
6965 * number floor(number)
6966 * The floor function returns the largest (closest to positive infinity)
6967 * number that is not greater than the argument and that is an integer.
6968 */
6969void
6970xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006971 double f;
6972
Owen Taylor3473f882001-02-23 17:55:21 +00006973 CHECK_ARITY(1);
6974 CAST_TO_NUMBER;
6975 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006976
6977 f = (double)((int) ctxt->value->floatval);
6978 if (f != ctxt->value->floatval) {
6979 if (ctxt->value->floatval > 0)
6980 ctxt->value->floatval = f;
6981 else
6982 ctxt->value->floatval = f - 1;
6983 }
Owen Taylor3473f882001-02-23 17:55:21 +00006984}
6985
6986/**
6987 * xmlXPathCeilingFunction:
6988 * @ctxt: the XPath Parser context
6989 * @nargs: the number of arguments
6990 *
6991 * Implement the ceiling() XPath function
6992 * number ceiling(number)
6993 * The ceiling function returns the smallest (closest to negative infinity)
6994 * number that is not less than the argument and that is an integer.
6995 */
6996void
6997xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6998 double f;
6999
7000 CHECK_ARITY(1);
7001 CAST_TO_NUMBER;
7002 CHECK_TYPE(XPATH_NUMBER);
7003
7004#if 0
7005 ctxt->value->floatval = ceil(ctxt->value->floatval);
7006#else
7007 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007008 if (f != ctxt->value->floatval) {
7009 if (ctxt->value->floatval > 0)
7010 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007011 else {
7012 if (ctxt->value->floatval < 0 && f == 0)
7013 ctxt->value->floatval = xmlXPathNZERO;
7014 else
7015 ctxt->value->floatval = f;
7016 }
7017
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007018 }
Owen Taylor3473f882001-02-23 17:55:21 +00007019#endif
7020}
7021
7022/**
7023 * xmlXPathRoundFunction:
7024 * @ctxt: the XPath Parser context
7025 * @nargs: the number of arguments
7026 *
7027 * Implement the round() XPath function
7028 * number round(number)
7029 * The round function returns the number that is closest to the
7030 * argument and that is an integer. If there are two such numbers,
7031 * then the one that is even is returned.
7032 */
7033void
7034xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7035 double f;
7036
7037 CHECK_ARITY(1);
7038 CAST_TO_NUMBER;
7039 CHECK_TYPE(XPATH_NUMBER);
7040
Daniel Veillardcda96922001-08-21 10:56:31 +00007041 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
7042 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
7043 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007044 (ctxt->value->floatval == 0.0))
7045 return;
7046
Owen Taylor3473f882001-02-23 17:55:21 +00007047 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007048 if (ctxt->value->floatval < 0) {
7049 if (ctxt->value->floatval < f - 0.5)
7050 ctxt->value->floatval = f - 1;
7051 else
7052 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007053 if (ctxt->value->floatval == 0)
7054 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007055 } else {
7056 if (ctxt->value->floatval < f + 0.5)
7057 ctxt->value->floatval = f;
7058 else
7059 ctxt->value->floatval = f + 1;
7060 }
Owen Taylor3473f882001-02-23 17:55:21 +00007061}
7062
7063/************************************************************************
7064 * *
7065 * The Parser *
7066 * *
7067 ************************************************************************/
7068
7069/*
7070 * a couple of forward declarations since we use a recursive call based
7071 * implementation.
7072 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007073static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007074static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007075static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007076static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00007077static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
7078 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00007079
7080/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00007081 * xmlXPathCurrentChar:
7082 * @ctxt: the XPath parser context
7083 * @cur: pointer to the beginning of the char
7084 * @len: pointer to the length of the char read
7085 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007086 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00007087 * bytes in the input buffer.
7088 *
Daniel Veillard60087f32001-10-10 09:45:09 +00007089 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00007090 */
7091
7092static int
7093xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
7094 unsigned char c;
7095 unsigned int val;
7096 const xmlChar *cur;
7097
7098 if (ctxt == NULL)
7099 return(0);
7100 cur = ctxt->cur;
7101
7102 /*
7103 * We are supposed to handle UTF8, check it's valid
7104 * From rfc2044: encoding of the Unicode values on UTF-8:
7105 *
7106 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
7107 * 0000 0000-0000 007F 0xxxxxxx
7108 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
7109 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
7110 *
7111 * Check for the 0x110000 limit too
7112 */
7113 c = *cur;
7114 if (c & 0x80) {
7115 if ((cur[1] & 0xc0) != 0x80)
7116 goto encoding_error;
7117 if ((c & 0xe0) == 0xe0) {
7118
7119 if ((cur[2] & 0xc0) != 0x80)
7120 goto encoding_error;
7121 if ((c & 0xf0) == 0xf0) {
7122 if (((c & 0xf8) != 0xf0) ||
7123 ((cur[3] & 0xc0) != 0x80))
7124 goto encoding_error;
7125 /* 4-byte code */
7126 *len = 4;
7127 val = (cur[0] & 0x7) << 18;
7128 val |= (cur[1] & 0x3f) << 12;
7129 val |= (cur[2] & 0x3f) << 6;
7130 val |= cur[3] & 0x3f;
7131 } else {
7132 /* 3-byte code */
7133 *len = 3;
7134 val = (cur[0] & 0xf) << 12;
7135 val |= (cur[1] & 0x3f) << 6;
7136 val |= cur[2] & 0x3f;
7137 }
7138 } else {
7139 /* 2-byte code */
7140 *len = 2;
7141 val = (cur[0] & 0x1f) << 6;
7142 val |= cur[1] & 0x3f;
7143 }
7144 if (!IS_CHAR(val)) {
7145 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
7146 }
7147 return(val);
7148 } else {
7149 /* 1-byte code */
7150 *len = 1;
7151 return((int) *cur);
7152 }
7153encoding_error:
7154 /*
7155 * If we detect an UTF8 error that probably mean that the
7156 * input encoding didn't get properly advertized in the
7157 * declaration header. Report the error and switch the encoding
7158 * to ISO-Latin-1 (if you don't like this policy, just declare the
7159 * encoding !)
7160 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00007161 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00007162 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007163}
7164
7165/**
Owen Taylor3473f882001-02-23 17:55:21 +00007166 * xmlXPathParseNCName:
7167 * @ctxt: the XPath Parser context
7168 *
7169 * parse an XML namespace non qualified name.
7170 *
7171 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7172 *
7173 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7174 * CombiningChar | Extender
7175 *
7176 * Returns the namespace name or NULL
7177 */
7178
7179xmlChar *
7180xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00007181 const xmlChar *in;
7182 xmlChar *ret;
7183 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007184
Daniel Veillard2156a562001-04-28 12:24:34 +00007185 /*
7186 * Accelerator for simple ASCII names
7187 */
7188 in = ctxt->cur;
7189 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7190 ((*in >= 0x41) && (*in <= 0x5A)) ||
7191 (*in == '_')) {
7192 in++;
7193 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7194 ((*in >= 0x41) && (*in <= 0x5A)) ||
7195 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00007196 (*in == '_') || (*in == '.') ||
7197 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00007198 in++;
7199 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7200 (*in == '[') || (*in == ']') || (*in == ':') ||
7201 (*in == '@') || (*in == '*')) {
7202 count = in - ctxt->cur;
7203 if (count == 0)
7204 return(NULL);
7205 ret = xmlStrndup(ctxt->cur, count);
7206 ctxt->cur = in;
7207 return(ret);
7208 }
7209 }
7210 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00007211}
7212
Daniel Veillard2156a562001-04-28 12:24:34 +00007213
Owen Taylor3473f882001-02-23 17:55:21 +00007214/**
7215 * xmlXPathParseQName:
7216 * @ctxt: the XPath Parser context
7217 * @prefix: a xmlChar **
7218 *
7219 * parse an XML qualified name
7220 *
7221 * [NS 5] QName ::= (Prefix ':')? LocalPart
7222 *
7223 * [NS 6] Prefix ::= NCName
7224 *
7225 * [NS 7] LocalPart ::= NCName
7226 *
7227 * Returns the function returns the local part, and prefix is updated
7228 * to get the Prefix if any.
7229 */
7230
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007231static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007232xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7233 xmlChar *ret = NULL;
7234
7235 *prefix = NULL;
7236 ret = xmlXPathParseNCName(ctxt);
7237 if (CUR == ':') {
7238 *prefix = ret;
7239 NEXT;
7240 ret = xmlXPathParseNCName(ctxt);
7241 }
7242 return(ret);
7243}
7244
7245/**
7246 * xmlXPathParseName:
7247 * @ctxt: the XPath Parser context
7248 *
7249 * parse an XML name
7250 *
7251 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7252 * CombiningChar | Extender
7253 *
7254 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7255 *
7256 * Returns the namespace name or NULL
7257 */
7258
7259xmlChar *
7260xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007261 const xmlChar *in;
7262 xmlChar *ret;
7263 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007264
Daniel Veillard61d80a22001-04-27 17:13:01 +00007265 /*
7266 * Accelerator for simple ASCII names
7267 */
7268 in = ctxt->cur;
7269 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7270 ((*in >= 0x41) && (*in <= 0x5A)) ||
7271 (*in == '_') || (*in == ':')) {
7272 in++;
7273 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7274 ((*in >= 0x41) && (*in <= 0x5A)) ||
7275 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00007276 (*in == '_') || (*in == '-') ||
7277 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00007278 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007279 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007280 count = in - ctxt->cur;
7281 ret = xmlStrndup(ctxt->cur, count);
7282 ctxt->cur = in;
7283 return(ret);
7284 }
7285 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007286 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00007287}
7288
Daniel Veillard61d80a22001-04-27 17:13:01 +00007289static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00007290xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007291 xmlChar buf[XML_MAX_NAMELEN + 5];
7292 int len = 0, l;
7293 int c;
7294
7295 /*
7296 * Handler for more complex cases
7297 */
7298 c = CUR_CHAR(l);
7299 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00007300 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7301 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00007302 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00007303 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007304 return(NULL);
7305 }
7306
7307 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7308 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7309 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007310 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007311 (IS_COMBINING(c)) ||
7312 (IS_EXTENDER(c)))) {
7313 COPY_BUF(l,buf,len,c);
7314 NEXTL(l);
7315 c = CUR_CHAR(l);
7316 if (len >= XML_MAX_NAMELEN) {
7317 /*
7318 * Okay someone managed to make a huge name, so he's ready to pay
7319 * for the processing speed.
7320 */
7321 xmlChar *buffer;
7322 int max = len * 2;
7323
Daniel Veillard3c908dc2003-04-19 00:07:51 +00007324 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007325 if (buffer == NULL) {
7326 XP_ERROR0(XPATH_MEMORY_ERROR);
7327 }
7328 memcpy(buffer, buf, len);
7329 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7330 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007331 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007332 (IS_COMBINING(c)) ||
7333 (IS_EXTENDER(c))) {
7334 if (len + 10 > max) {
7335 max *= 2;
7336 buffer = (xmlChar *) xmlRealloc(buffer,
7337 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007338 if (buffer == NULL) {
7339 XP_ERROR0(XPATH_MEMORY_ERROR);
7340 }
7341 }
7342 COPY_BUF(l,buffer,len,c);
7343 NEXTL(l);
7344 c = CUR_CHAR(l);
7345 }
7346 buffer[len] = 0;
7347 return(buffer);
7348 }
7349 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007350 if (len == 0)
7351 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007352 return(xmlStrndup(buf, len));
7353}
Daniel Veillard3cd72402002-05-13 10:33:30 +00007354
7355#define MAX_FRAC 20
7356
7357static double my_pow10[MAX_FRAC] = {
7358 1.0, 10.0, 100.0, 1000.0, 10000.0,
7359 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7360 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7361 100000000000000.0,
7362 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
7363 1000000000000000000.0, 10000000000000000000.0
7364};
7365
Owen Taylor3473f882001-02-23 17:55:21 +00007366/**
7367 * xmlXPathStringEvalNumber:
7368 * @str: A string to scan
7369 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00007370 * [30a] Float ::= Number ('e' Digits?)?
7371 *
Owen Taylor3473f882001-02-23 17:55:21 +00007372 * [30] Number ::= Digits ('.' Digits?)?
7373 * | '.' Digits
7374 * [31] Digits ::= [0-9]+
7375 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007376 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00007377 * In complement of the Number expression, this function also handles
7378 * negative values : '-' Number.
7379 *
7380 * Returns the double value.
7381 */
7382double
7383xmlXPathStringEvalNumber(const xmlChar *str) {
7384 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00007385 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007386 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007387 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007388 int exponent = 0;
7389 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007390#ifdef __GNUC__
7391 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007392 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007393#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00007394 if (cur == NULL) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00007395 while (IS_BLANK(*cur)) cur++;
7396 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7397 return(xmlXPathNAN);
7398 }
7399 if (*cur == '-') {
7400 isneg = 1;
7401 cur++;
7402 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007403
7404#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007405 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007406 * tmp/temp is a workaround against a gcc compiler bug
7407 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007408 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007409 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007410 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007411 ret = ret * 10;
7412 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00007413 ok = 1;
7414 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00007415 temp = (double) tmp;
7416 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007417 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007418#else
Daniel Veillard7b416132002-03-07 08:36:03 +00007419 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007420 while ((*cur >= '0') && (*cur <= '9')) {
7421 ret = ret * 10 + (*cur - '0');
7422 ok = 1;
7423 cur++;
7424 }
7425#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007426
Owen Taylor3473f882001-02-23 17:55:21 +00007427 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007428 int v, frac = 0;
7429 double fraction = 0;
7430
Owen Taylor3473f882001-02-23 17:55:21 +00007431 cur++;
7432 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7433 return(xmlXPathNAN);
7434 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007435 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
7436 v = (*cur - '0');
7437 fraction = fraction * 10 + v;
7438 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007439 cur++;
7440 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007441 fraction /= my_pow10[frac];
7442 ret = ret + fraction;
7443 while ((*cur >= '0') && (*cur <= '9'))
7444 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007445 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007446 if ((*cur == 'e') || (*cur == 'E')) {
7447 cur++;
7448 if (*cur == '-') {
7449 is_exponent_negative = 1;
7450 cur++;
7451 }
7452 while ((*cur >= '0') && (*cur <= '9')) {
7453 exponent = exponent * 10 + (*cur - '0');
7454 cur++;
7455 }
7456 }
Owen Taylor3473f882001-02-23 17:55:21 +00007457 while (IS_BLANK(*cur)) cur++;
7458 if (*cur != 0) return(xmlXPathNAN);
7459 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007460 if (is_exponent_negative) exponent = -exponent;
7461 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007462 return(ret);
7463}
7464
7465/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007466 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007467 * @ctxt: the XPath Parser context
7468 *
7469 * [30] Number ::= Digits ('.' Digits?)?
7470 * | '.' Digits
7471 * [31] Digits ::= [0-9]+
7472 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007473 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007474 *
7475 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007476static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007477xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7478{
Owen Taylor3473f882001-02-23 17:55:21 +00007479 double ret = 0.0;
7480 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007481 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007482 int exponent = 0;
7483 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007484#ifdef __GNUC__
7485 unsigned long tmp = 0;
7486 double temp;
7487#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007488
7489 CHECK_ERROR;
7490 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7491 XP_ERROR(XPATH_NUMBER_ERROR);
7492 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007493#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007494 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007495 * tmp/temp is a workaround against a gcc compiler bug
7496 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007497 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007498 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007499 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007500 ret = ret * 10;
7501 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007502 ok = 1;
7503 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007504 temp = (double) tmp;
7505 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007506 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007507#else
7508 ret = 0;
7509 while ((CUR >= '0') && (CUR <= '9')) {
7510 ret = ret * 10 + (CUR - '0');
7511 ok = 1;
7512 NEXT;
7513 }
7514#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007515 if (CUR == '.') {
7516 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007517 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7518 XP_ERROR(XPATH_NUMBER_ERROR);
7519 }
7520 while ((CUR >= '0') && (CUR <= '9')) {
7521 mult /= 10;
7522 ret = ret + (CUR - '0') * mult;
7523 NEXT;
7524 }
Owen Taylor3473f882001-02-23 17:55:21 +00007525 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007526 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007527 NEXT;
7528 if (CUR == '-') {
7529 is_exponent_negative = 1;
7530 NEXT;
7531 }
7532 while ((CUR >= '0') && (CUR <= '9')) {
7533 exponent = exponent * 10 + (CUR - '0');
7534 NEXT;
7535 }
7536 if (is_exponent_negative)
7537 exponent = -exponent;
7538 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007539 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007540 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007541 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007542}
7543
7544/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007545 * xmlXPathParseLiteral:
7546 * @ctxt: the XPath Parser context
7547 *
7548 * Parse a Literal
7549 *
7550 * [29] Literal ::= '"' [^"]* '"'
7551 * | "'" [^']* "'"
7552 *
7553 * Returns the value found or NULL in case of error
7554 */
7555static xmlChar *
7556xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7557 const xmlChar *q;
7558 xmlChar *ret = NULL;
7559
7560 if (CUR == '"') {
7561 NEXT;
7562 q = CUR_PTR;
7563 while ((IS_CHAR(CUR)) && (CUR != '"'))
7564 NEXT;
7565 if (!IS_CHAR(CUR)) {
7566 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7567 } else {
7568 ret = xmlStrndup(q, CUR_PTR - q);
7569 NEXT;
7570 }
7571 } else if (CUR == '\'') {
7572 NEXT;
7573 q = CUR_PTR;
7574 while ((IS_CHAR(CUR)) && (CUR != '\''))
7575 NEXT;
7576 if (!IS_CHAR(CUR)) {
7577 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7578 } else {
7579 ret = xmlStrndup(q, CUR_PTR - q);
7580 NEXT;
7581 }
7582 } else {
7583 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7584 }
7585 return(ret);
7586}
7587
7588/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007589 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007590 * @ctxt: the XPath Parser context
7591 *
7592 * Parse a Literal and push it on the stack.
7593 *
7594 * [29] Literal ::= '"' [^"]* '"'
7595 * | "'" [^']* "'"
7596 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007597 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007598 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007599static void
7600xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007601 const xmlChar *q;
7602 xmlChar *ret = NULL;
7603
7604 if (CUR == '"') {
7605 NEXT;
7606 q = CUR_PTR;
7607 while ((IS_CHAR(CUR)) && (CUR != '"'))
7608 NEXT;
7609 if (!IS_CHAR(CUR)) {
7610 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7611 } else {
7612 ret = xmlStrndup(q, CUR_PTR - q);
7613 NEXT;
7614 }
7615 } else if (CUR == '\'') {
7616 NEXT;
7617 q = CUR_PTR;
7618 while ((IS_CHAR(CUR)) && (CUR != '\''))
7619 NEXT;
7620 if (!IS_CHAR(CUR)) {
7621 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7622 } else {
7623 ret = xmlStrndup(q, CUR_PTR - q);
7624 NEXT;
7625 }
7626 } else {
7627 XP_ERROR(XPATH_START_LITERAL_ERROR);
7628 }
7629 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007630 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7631 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007632 xmlFree(ret);
7633}
7634
7635/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007636 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007637 * @ctxt: the XPath Parser context
7638 *
7639 * Parse a VariableReference, evaluate it and push it on the stack.
7640 *
7641 * The variable bindings consist of a mapping from variable names
7642 * to variable values. The value of a variable is an object, which
7643 * of any of the types that are possible for the value of an expression,
7644 * and may also be of additional types not specified here.
7645 *
7646 * Early evaluation is possible since:
7647 * The variable bindings [...] used to evaluate a subexpression are
7648 * always the same as those used to evaluate the containing expression.
7649 *
7650 * [36] VariableReference ::= '$' QName
7651 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007652static void
7653xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007654 xmlChar *name;
7655 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007656
7657 SKIP_BLANKS;
7658 if (CUR != '$') {
7659 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7660 }
7661 NEXT;
7662 name = xmlXPathParseQName(ctxt, &prefix);
7663 if (name == NULL) {
7664 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7665 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007666 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007667 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7668 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007669 SKIP_BLANKS;
7670}
7671
7672/**
7673 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +00007674 * @name: a name string
7675 *
7676 * Is the name given a NodeType one.
7677 *
7678 * [38] NodeType ::= 'comment'
7679 * | 'text'
7680 * | 'processing-instruction'
7681 * | 'node'
7682 *
7683 * Returns 1 if true 0 otherwise
7684 */
7685int
7686xmlXPathIsNodeType(const xmlChar *name) {
7687 if (name == NULL)
7688 return(0);
7689
Daniel Veillard1971ee22002-01-31 20:29:19 +00007690 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007691 return(1);
7692 if (xmlStrEqual(name, BAD_CAST "text"))
7693 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007694 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007695 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007696 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007697 return(1);
7698 return(0);
7699}
7700
7701/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007702 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007703 * @ctxt: the XPath Parser context
7704 *
7705 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7706 * [17] Argument ::= Expr
7707 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007708 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007709 * pushed on the stack
7710 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007711static void
7712xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007713 xmlChar *name;
7714 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007715 int nbargs = 0;
7716
7717 name = xmlXPathParseQName(ctxt, &prefix);
7718 if (name == NULL) {
7719 XP_ERROR(XPATH_EXPR_ERROR);
7720 }
7721 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007722#ifdef DEBUG_EXPR
7723 if (prefix == NULL)
7724 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7725 name);
7726 else
7727 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7728 prefix, name);
7729#endif
7730
Owen Taylor3473f882001-02-23 17:55:21 +00007731 if (CUR != '(') {
7732 XP_ERROR(XPATH_EXPR_ERROR);
7733 }
7734 NEXT;
7735 SKIP_BLANKS;
7736
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007737 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +00007738 if (CUR != ')') {
7739 while (CUR != 0) {
7740 int op1 = ctxt->comp->last;
7741 ctxt->comp->last = -1;
7742 xmlXPathCompileExpr(ctxt);
7743 CHECK_ERROR;
7744 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
7745 nbargs++;
7746 if (CUR == ')') break;
7747 if (CUR != ',') {
7748 XP_ERROR(XPATH_EXPR_ERROR);
7749 }
7750 NEXT;
7751 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007752 }
Owen Taylor3473f882001-02-23 17:55:21 +00007753 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007754 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7755 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007756 NEXT;
7757 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007758}
7759
7760/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007761 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007762 * @ctxt: the XPath Parser context
7763 *
7764 * [15] PrimaryExpr ::= VariableReference
7765 * | '(' Expr ')'
7766 * | Literal
7767 * | Number
7768 * | FunctionCall
7769 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007770 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007771 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007772static void
7773xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007774 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007775 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007776 else if (CUR == '(') {
7777 NEXT;
7778 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007779 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007780 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00007781 if (CUR != ')') {
7782 XP_ERROR(XPATH_EXPR_ERROR);
7783 }
7784 NEXT;
7785 SKIP_BLANKS;
Daniel Veillard01917aa2002-04-10 11:30:41 +00007786 } else if (IS_DIGIT(CUR) || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007787 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007788 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007789 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007790 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007791 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007792 }
7793 SKIP_BLANKS;
7794}
7795
7796/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007797 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007798 * @ctxt: the XPath Parser context
7799 *
7800 * [20] FilterExpr ::= PrimaryExpr
7801 * | FilterExpr Predicate
7802 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007803 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007804 * Square brackets are used to filter expressions in the same way that
7805 * they are used in location paths. It is an error if the expression to
7806 * be filtered does not evaluate to a node-set. The context node list
7807 * used for evaluating the expression in square brackets is the node-set
7808 * to be filtered listed in document order.
7809 */
7810
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007811static void
7812xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
7813 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007814 CHECK_ERROR;
7815 SKIP_BLANKS;
7816
7817 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007818 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00007819 SKIP_BLANKS;
7820 }
7821
7822
7823}
7824
7825/**
7826 * xmlXPathScanName:
7827 * @ctxt: the XPath Parser context
7828 *
7829 * Trickery: parse an XML name but without consuming the input flow
7830 * Needed to avoid insanity in the parser state.
7831 *
7832 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7833 * CombiningChar | Extender
7834 *
7835 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7836 *
7837 * [6] Names ::= Name (S Name)*
7838 *
7839 * Returns the Name parsed or NULL
7840 */
7841
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007842static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007843xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7844 xmlChar buf[XML_MAX_NAMELEN];
7845 int len = 0;
7846
7847 SKIP_BLANKS;
7848 if (!IS_LETTER(CUR) && (CUR != '_') &&
7849 (CUR != ':')) {
7850 return(NULL);
7851 }
7852
7853 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7854 (NXT(len) == '.') || (NXT(len) == '-') ||
7855 (NXT(len) == '_') || (NXT(len) == ':') ||
7856 (IS_COMBINING(NXT(len))) ||
7857 (IS_EXTENDER(NXT(len)))) {
7858 buf[len] = NXT(len);
7859 len++;
7860 if (len >= XML_MAX_NAMELEN) {
7861 xmlGenericError(xmlGenericErrorContext,
7862 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
7863 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7864 (NXT(len) == '.') || (NXT(len) == '-') ||
7865 (NXT(len) == '_') || (NXT(len) == ':') ||
7866 (IS_COMBINING(NXT(len))) ||
7867 (IS_EXTENDER(NXT(len))))
7868 len++;
7869 break;
7870 }
7871 }
7872 return(xmlStrndup(buf, len));
7873}
7874
7875/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007876 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007877 * @ctxt: the XPath Parser context
7878 *
7879 * [19] PathExpr ::= LocationPath
7880 * | FilterExpr
7881 * | FilterExpr '/' RelativeLocationPath
7882 * | FilterExpr '//' RelativeLocationPath
7883 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007884 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007885 * The / operator and // operators combine an arbitrary expression
7886 * and a relative location path. It is an error if the expression
7887 * does not evaluate to a node-set.
7888 * The / operator does composition in the same way as when / is
7889 * used in a location path. As in location paths, // is short for
7890 * /descendant-or-self::node()/.
7891 */
7892
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007893static void
7894xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007895 int lc = 1; /* Should we branch to LocationPath ? */
7896 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7897
7898 SKIP_BLANKS;
7899 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
Daniel Veillard01917aa2002-04-10 11:30:41 +00007900 (CUR == '\'') || (CUR == '"') || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00007901 lc = 0;
7902 } else if (CUR == '*') {
7903 /* relative or absolute location path */
7904 lc = 1;
7905 } else if (CUR == '/') {
7906 /* relative or absolute location path */
7907 lc = 1;
7908 } else if (CUR == '@') {
7909 /* relative abbreviated attribute location path */
7910 lc = 1;
7911 } else if (CUR == '.') {
7912 /* relative abbreviated attribute location path */
7913 lc = 1;
7914 } else {
7915 /*
7916 * Problem is finding if we have a name here whether it's:
7917 * - a nodetype
7918 * - a function call in which case it's followed by '('
7919 * - an axis in which case it's followed by ':'
7920 * - a element name
7921 * We do an a priori analysis here rather than having to
7922 * maintain parsed token content through the recursive function
7923 * calls. This looks uglier but makes the code quite easier to
7924 * read/write/debug.
7925 */
7926 SKIP_BLANKS;
7927 name = xmlXPathScanName(ctxt);
7928 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7929#ifdef DEBUG_STEP
7930 xmlGenericError(xmlGenericErrorContext,
7931 "PathExpr: Axis\n");
7932#endif
7933 lc = 1;
7934 xmlFree(name);
7935 } else if (name != NULL) {
7936 int len =xmlStrlen(name);
7937 int blank = 0;
7938
7939
7940 while (NXT(len) != 0) {
7941 if (NXT(len) == '/') {
7942 /* element name */
7943#ifdef DEBUG_STEP
7944 xmlGenericError(xmlGenericErrorContext,
7945 "PathExpr: AbbrRelLocation\n");
7946#endif
7947 lc = 1;
7948 break;
7949 } else if (IS_BLANK(NXT(len))) {
7950 /* skip to next */
7951 blank = 1;
7952 } else if (NXT(len) == ':') {
7953#ifdef DEBUG_STEP
7954 xmlGenericError(xmlGenericErrorContext,
7955 "PathExpr: AbbrRelLocation\n");
7956#endif
7957 lc = 1;
7958 break;
7959 } else if ((NXT(len) == '(')) {
7960 /* Note Type or Function */
7961 if (xmlXPathIsNodeType(name)) {
7962#ifdef DEBUG_STEP
7963 xmlGenericError(xmlGenericErrorContext,
7964 "PathExpr: Type search\n");
7965#endif
7966 lc = 1;
7967 } else {
7968#ifdef DEBUG_STEP
7969 xmlGenericError(xmlGenericErrorContext,
7970 "PathExpr: function call\n");
7971#endif
7972 lc = 0;
7973 }
7974 break;
7975 } else if ((NXT(len) == '[')) {
7976 /* element name */
7977#ifdef DEBUG_STEP
7978 xmlGenericError(xmlGenericErrorContext,
7979 "PathExpr: AbbrRelLocation\n");
7980#endif
7981 lc = 1;
7982 break;
7983 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
7984 (NXT(len) == '=')) {
7985 lc = 1;
7986 break;
7987 } else {
7988 lc = 1;
7989 break;
7990 }
7991 len++;
7992 }
7993 if (NXT(len) == 0) {
7994#ifdef DEBUG_STEP
7995 xmlGenericError(xmlGenericErrorContext,
7996 "PathExpr: AbbrRelLocation\n");
7997#endif
7998 /* element name */
7999 lc = 1;
8000 }
8001 xmlFree(name);
8002 } else {
8003 /* make sure all cases are covered explicitely */
8004 XP_ERROR(XPATH_EXPR_ERROR);
8005 }
8006 }
8007
8008 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008009 if (CUR == '/') {
8010 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8011 } else {
8012 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008013 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008014 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008015 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008016 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008017 CHECK_ERROR;
8018 if ((CUR == '/') && (NXT(1) == '/')) {
8019 SKIP(2);
8020 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008021
8022 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8023 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8024 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
8025
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008026 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008027 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008028 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008029 }
8030 }
8031 SKIP_BLANKS;
8032}
8033
8034/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008035 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008036 * @ctxt: the XPath Parser context
8037 *
8038 * [18] UnionExpr ::= PathExpr
8039 * | UnionExpr '|' PathExpr
8040 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008041 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008042 */
8043
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008044static void
8045xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8046 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008047 CHECK_ERROR;
8048 SKIP_BLANKS;
8049 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008050 int op1 = ctxt->comp->last;
8051 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008052
8053 NEXT;
8054 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008055 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008056
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008057 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8058
Owen Taylor3473f882001-02-23 17:55:21 +00008059 SKIP_BLANKS;
8060 }
Owen Taylor3473f882001-02-23 17:55:21 +00008061}
8062
8063/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008064 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008065 * @ctxt: the XPath Parser context
8066 *
8067 * [27] UnaryExpr ::= UnionExpr
8068 * | '-' UnaryExpr
8069 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008070 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008071 */
8072
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008073static void
8074xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008075 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008076 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008077
8078 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00008079 while (CUR == '-') {
8080 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008081 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008082 NEXT;
8083 SKIP_BLANKS;
8084 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008085
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008086 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008087 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008088 if (found) {
8089 if (minus)
8090 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8091 else
8092 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008093 }
8094}
8095
8096/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008097 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008098 * @ctxt: the XPath Parser context
8099 *
8100 * [26] MultiplicativeExpr ::= UnaryExpr
8101 * | MultiplicativeExpr MultiplyOperator UnaryExpr
8102 * | MultiplicativeExpr 'div' UnaryExpr
8103 * | MultiplicativeExpr 'mod' UnaryExpr
8104 * [34] MultiplyOperator ::= '*'
8105 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008106 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008107 */
8108
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008109static void
8110xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8111 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008112 CHECK_ERROR;
8113 SKIP_BLANKS;
8114 while ((CUR == '*') ||
8115 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8116 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8117 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008118 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008119
8120 if (CUR == '*') {
8121 op = 0;
8122 NEXT;
8123 } else if (CUR == 'd') {
8124 op = 1;
8125 SKIP(3);
8126 } else if (CUR == 'm') {
8127 op = 2;
8128 SKIP(3);
8129 }
8130 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008131 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008132 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008133 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008134 SKIP_BLANKS;
8135 }
8136}
8137
8138/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008139 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008140 * @ctxt: the XPath Parser context
8141 *
8142 * [25] AdditiveExpr ::= MultiplicativeExpr
8143 * | AdditiveExpr '+' MultiplicativeExpr
8144 * | AdditiveExpr '-' MultiplicativeExpr
8145 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008146 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008147 */
8148
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008149static void
8150xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008151
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008152 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008153 CHECK_ERROR;
8154 SKIP_BLANKS;
8155 while ((CUR == '+') || (CUR == '-')) {
8156 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008157 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008158
8159 if (CUR == '+') plus = 1;
8160 else plus = 0;
8161 NEXT;
8162 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008163 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008164 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008165 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008166 SKIP_BLANKS;
8167 }
8168}
8169
8170/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008171 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008172 * @ctxt: the XPath Parser context
8173 *
8174 * [24] RelationalExpr ::= AdditiveExpr
8175 * | RelationalExpr '<' AdditiveExpr
8176 * | RelationalExpr '>' AdditiveExpr
8177 * | RelationalExpr '<=' AdditiveExpr
8178 * | RelationalExpr '>=' AdditiveExpr
8179 *
8180 * A <= B > C is allowed ? Answer from James, yes with
8181 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8182 * which is basically what got implemented.
8183 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008184 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00008185 * on the stack
8186 */
8187
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008188static void
8189xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8190 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008191 CHECK_ERROR;
8192 SKIP_BLANKS;
8193 while ((CUR == '<') ||
8194 (CUR == '>') ||
8195 ((CUR == '<') && (NXT(1) == '=')) ||
8196 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008197 int inf, strict;
8198 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008199
8200 if (CUR == '<') inf = 1;
8201 else inf = 0;
8202 if (NXT(1) == '=') strict = 0;
8203 else strict = 1;
8204 NEXT;
8205 if (!strict) NEXT;
8206 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008207 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008208 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008209 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00008210 SKIP_BLANKS;
8211 }
8212}
8213
8214/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008215 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008216 * @ctxt: the XPath Parser context
8217 *
8218 * [23] EqualityExpr ::= RelationalExpr
8219 * | EqualityExpr '=' RelationalExpr
8220 * | EqualityExpr '!=' RelationalExpr
8221 *
8222 * A != B != C is allowed ? Answer from James, yes with
8223 * (RelationalExpr = RelationalExpr) = RelationalExpr
8224 * (RelationalExpr != RelationalExpr) != RelationalExpr
8225 * which is basically what got implemented.
8226 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008227 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008228 *
8229 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008230static void
8231xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8232 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008233 CHECK_ERROR;
8234 SKIP_BLANKS;
8235 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008236 int eq;
8237 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008238
8239 if (CUR == '=') eq = 1;
8240 else eq = 0;
8241 NEXT;
8242 if (!eq) NEXT;
8243 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008244 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008245 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008246 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008247 SKIP_BLANKS;
8248 }
8249}
8250
8251/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008252 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008253 * @ctxt: the XPath Parser context
8254 *
8255 * [22] AndExpr ::= EqualityExpr
8256 * | AndExpr 'and' EqualityExpr
8257 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008258 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008259 *
8260 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008261static void
8262xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8263 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008264 CHECK_ERROR;
8265 SKIP_BLANKS;
8266 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008267 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008268 SKIP(3);
8269 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008270 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008271 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008272 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008273 SKIP_BLANKS;
8274 }
8275}
8276
8277/**
Daniel Veillard591b4be2003-02-09 23:33:36 +00008278 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008279 * @ctxt: the XPath Parser context
8280 *
8281 * [14] Expr ::= OrExpr
8282 * [21] OrExpr ::= AndExpr
8283 * | OrExpr 'or' AndExpr
8284 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008285 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00008286 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008287static void
8288xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8289 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008290 CHECK_ERROR;
8291 SKIP_BLANKS;
8292 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008293 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008294 SKIP(2);
8295 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008296 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008297 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008298 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8299 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00008300 SKIP_BLANKS;
8301 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008302 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8303 /* more ops could be optimized too */
8304 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8305 }
Owen Taylor3473f882001-02-23 17:55:21 +00008306}
8307
8308/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008309 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00008310 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008311 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00008312 *
8313 * [8] Predicate ::= '[' PredicateExpr ']'
8314 * [9] PredicateExpr ::= Expr
8315 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008316 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008317 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008318static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008319xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008320 int op1 = ctxt->comp->last;
8321
8322 SKIP_BLANKS;
8323 if (CUR != '[') {
8324 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8325 }
8326 NEXT;
8327 SKIP_BLANKS;
8328
8329 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008330 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008331 CHECK_ERROR;
8332
8333 if (CUR != ']') {
8334 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8335 }
8336
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008337 if (filter)
8338 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8339 else
8340 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008341
8342 NEXT;
8343 SKIP_BLANKS;
8344}
8345
8346/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008347 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00008348 * @ctxt: the XPath Parser context
8349 * @test: pointer to a xmlXPathTestVal
8350 * @type: pointer to a xmlXPathTypeVal
8351 * @prefix: placeholder for a possible name prefix
8352 *
8353 * [7] NodeTest ::= NameTest
8354 * | NodeType '(' ')'
8355 * | 'processing-instruction' '(' Literal ')'
8356 *
8357 * [37] NameTest ::= '*'
8358 * | NCName ':' '*'
8359 * | QName
8360 * [38] NodeType ::= 'comment'
8361 * | 'text'
8362 * | 'processing-instruction'
8363 * | 'node'
8364 *
8365 * Returns the name found and update @test, @type and @prefix appropriately
8366 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008367static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008368xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8369 xmlXPathTypeVal *type, const xmlChar **prefix,
8370 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008371 int blanks;
8372
8373 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8374 STRANGE;
8375 return(NULL);
8376 }
8377 *type = 0;
8378 *test = 0;
8379 *prefix = NULL;
8380 SKIP_BLANKS;
8381
8382 if ((name == NULL) && (CUR == '*')) {
8383 /*
8384 * All elements
8385 */
8386 NEXT;
8387 *test = NODE_TEST_ALL;
8388 return(NULL);
8389 }
8390
8391 if (name == NULL)
8392 name = xmlXPathParseNCName(ctxt);
8393 if (name == NULL) {
8394 XP_ERROR0(XPATH_EXPR_ERROR);
8395 }
8396
8397 blanks = IS_BLANK(CUR);
8398 SKIP_BLANKS;
8399 if (CUR == '(') {
8400 NEXT;
8401 /*
8402 * NodeType or PI search
8403 */
8404 if (xmlStrEqual(name, BAD_CAST "comment"))
8405 *type = NODE_TYPE_COMMENT;
8406 else if (xmlStrEqual(name, BAD_CAST "node"))
8407 *type = NODE_TYPE_NODE;
8408 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8409 *type = NODE_TYPE_PI;
8410 else if (xmlStrEqual(name, BAD_CAST "text"))
8411 *type = NODE_TYPE_TEXT;
8412 else {
8413 if (name != NULL)
8414 xmlFree(name);
8415 XP_ERROR0(XPATH_EXPR_ERROR);
8416 }
8417
8418 *test = NODE_TEST_TYPE;
8419
8420 SKIP_BLANKS;
8421 if (*type == NODE_TYPE_PI) {
8422 /*
8423 * Specific case: search a PI by name.
8424 */
Owen Taylor3473f882001-02-23 17:55:21 +00008425 if (name != NULL)
8426 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008427 name = NULL;
8428 if (CUR != ')') {
8429 name = xmlXPathParseLiteral(ctxt);
8430 CHECK_ERROR 0;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00008431 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00008432 SKIP_BLANKS;
8433 }
Owen Taylor3473f882001-02-23 17:55:21 +00008434 }
8435 if (CUR != ')') {
8436 if (name != NULL)
8437 xmlFree(name);
8438 XP_ERROR0(XPATH_UNCLOSED_ERROR);
8439 }
8440 NEXT;
8441 return(name);
8442 }
8443 *test = NODE_TEST_NAME;
8444 if ((!blanks) && (CUR == ':')) {
8445 NEXT;
8446
8447 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008448 * Since currently the parser context don't have a
8449 * namespace list associated:
8450 * The namespace name for this prefix can be computed
8451 * only at evaluation time. The compilation is done
8452 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008453 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008454#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008455 *prefix = xmlXPathNsLookup(ctxt->context, name);
8456 if (name != NULL)
8457 xmlFree(name);
8458 if (*prefix == NULL) {
8459 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8460 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008461#else
8462 *prefix = name;
8463#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008464
8465 if (CUR == '*') {
8466 /*
8467 * All elements
8468 */
8469 NEXT;
8470 *test = NODE_TEST_ALL;
8471 return(NULL);
8472 }
8473
8474 name = xmlXPathParseNCName(ctxt);
8475 if (name == NULL) {
8476 XP_ERROR0(XPATH_EXPR_ERROR);
8477 }
8478 }
8479 return(name);
8480}
8481
8482/**
8483 * xmlXPathIsAxisName:
8484 * @name: a preparsed name token
8485 *
8486 * [6] AxisName ::= 'ancestor'
8487 * | 'ancestor-or-self'
8488 * | 'attribute'
8489 * | 'child'
8490 * | 'descendant'
8491 * | 'descendant-or-self'
8492 * | 'following'
8493 * | 'following-sibling'
8494 * | 'namespace'
8495 * | 'parent'
8496 * | 'preceding'
8497 * | 'preceding-sibling'
8498 * | 'self'
8499 *
8500 * Returns the axis or 0
8501 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008502static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008503xmlXPathIsAxisName(const xmlChar *name) {
8504 xmlXPathAxisVal ret = 0;
8505 switch (name[0]) {
8506 case 'a':
8507 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8508 ret = AXIS_ANCESTOR;
8509 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8510 ret = AXIS_ANCESTOR_OR_SELF;
8511 if (xmlStrEqual(name, BAD_CAST "attribute"))
8512 ret = AXIS_ATTRIBUTE;
8513 break;
8514 case 'c':
8515 if (xmlStrEqual(name, BAD_CAST "child"))
8516 ret = AXIS_CHILD;
8517 break;
8518 case 'd':
8519 if (xmlStrEqual(name, BAD_CAST "descendant"))
8520 ret = AXIS_DESCENDANT;
8521 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8522 ret = AXIS_DESCENDANT_OR_SELF;
8523 break;
8524 case 'f':
8525 if (xmlStrEqual(name, BAD_CAST "following"))
8526 ret = AXIS_FOLLOWING;
8527 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8528 ret = AXIS_FOLLOWING_SIBLING;
8529 break;
8530 case 'n':
8531 if (xmlStrEqual(name, BAD_CAST "namespace"))
8532 ret = AXIS_NAMESPACE;
8533 break;
8534 case 'p':
8535 if (xmlStrEqual(name, BAD_CAST "parent"))
8536 ret = AXIS_PARENT;
8537 if (xmlStrEqual(name, BAD_CAST "preceding"))
8538 ret = AXIS_PRECEDING;
8539 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8540 ret = AXIS_PRECEDING_SIBLING;
8541 break;
8542 case 's':
8543 if (xmlStrEqual(name, BAD_CAST "self"))
8544 ret = AXIS_SELF;
8545 break;
8546 }
8547 return(ret);
8548}
8549
8550/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008551 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008552 * @ctxt: the XPath Parser context
8553 *
8554 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8555 * | AbbreviatedStep
8556 *
8557 * [12] AbbreviatedStep ::= '.' | '..'
8558 *
8559 * [5] AxisSpecifier ::= AxisName '::'
8560 * | AbbreviatedAxisSpecifier
8561 *
8562 * [13] AbbreviatedAxisSpecifier ::= '@'?
8563 *
8564 * Modified for XPtr range support as:
8565 *
8566 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8567 * | AbbreviatedStep
8568 * | 'range-to' '(' Expr ')' Predicate*
8569 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008570 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008571 * A location step of . is short for self::node(). This is
8572 * particularly useful in conjunction with //. For example, the
8573 * location path .//para is short for
8574 * self::node()/descendant-or-self::node()/child::para
8575 * and so will select all para descendant elements of the context
8576 * node.
8577 * Similarly, a location step of .. is short for parent::node().
8578 * For example, ../title is short for parent::node()/child::title
8579 * and so will select the title children of the parent of the context
8580 * node.
8581 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008582static void
8583xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008584#ifdef LIBXML_XPTR_ENABLED
8585 int rangeto = 0;
8586 int op2 = -1;
8587#endif
8588
Owen Taylor3473f882001-02-23 17:55:21 +00008589 SKIP_BLANKS;
8590 if ((CUR == '.') && (NXT(1) == '.')) {
8591 SKIP(2);
8592 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008593 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8594 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008595 } else if (CUR == '.') {
8596 NEXT;
8597 SKIP_BLANKS;
8598 } else {
8599 xmlChar *name = NULL;
8600 const xmlChar *prefix = NULL;
8601 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008602 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008603 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008604 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008605
8606 /*
8607 * The modification needed for XPointer change to the production
8608 */
8609#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008610 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008611 name = xmlXPathParseNCName(ctxt);
8612 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008613 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008614 xmlFree(name);
8615 SKIP_BLANKS;
8616 if (CUR != '(') {
8617 XP_ERROR(XPATH_EXPR_ERROR);
8618 }
8619 NEXT;
8620 SKIP_BLANKS;
8621
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008622 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008623 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008624 CHECK_ERROR;
8625
8626 SKIP_BLANKS;
8627 if (CUR != ')') {
8628 XP_ERROR(XPATH_EXPR_ERROR);
8629 }
8630 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008631 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008632 goto eval_predicates;
8633 }
8634 }
8635#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008636 if (CUR == '*') {
8637 axis = AXIS_CHILD;
8638 } else {
8639 if (name == NULL)
8640 name = xmlXPathParseNCName(ctxt);
8641 if (name != NULL) {
8642 axis = xmlXPathIsAxisName(name);
8643 if (axis != 0) {
8644 SKIP_BLANKS;
8645 if ((CUR == ':') && (NXT(1) == ':')) {
8646 SKIP(2);
8647 xmlFree(name);
8648 name = NULL;
8649 } else {
8650 /* an element name can conflict with an axis one :-\ */
8651 axis = AXIS_CHILD;
8652 }
Owen Taylor3473f882001-02-23 17:55:21 +00008653 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008654 axis = AXIS_CHILD;
8655 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008656 } else if (CUR == '@') {
8657 NEXT;
8658 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008659 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008660 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008661 }
Owen Taylor3473f882001-02-23 17:55:21 +00008662 }
8663
8664 CHECK_ERROR;
8665
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008666 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008667 if (test == 0)
8668 return;
8669
8670#ifdef DEBUG_STEP
8671 xmlGenericError(xmlGenericErrorContext,
8672 "Basis : computing new set\n");
8673#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008674
Owen Taylor3473f882001-02-23 17:55:21 +00008675#ifdef DEBUG_STEP
8676 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008677 if (ctxt->value == NULL)
8678 xmlGenericError(xmlGenericErrorContext, "no value\n");
8679 else if (ctxt->value->nodesetval == NULL)
8680 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8681 else
8682 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008683#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008684
8685eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008686 op1 = ctxt->comp->last;
8687 ctxt->comp->last = -1;
8688
Owen Taylor3473f882001-02-23 17:55:21 +00008689 SKIP_BLANKS;
8690 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008691 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008692 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008693
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008694#ifdef LIBXML_XPTR_ENABLED
8695 if (rangeto) {
8696 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8697 } else
8698#endif
8699 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8700 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008701
Owen Taylor3473f882001-02-23 17:55:21 +00008702 }
8703#ifdef DEBUG_STEP
8704 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008705 if (ctxt->value == NULL)
8706 xmlGenericError(xmlGenericErrorContext, "no value\n");
8707 else if (ctxt->value->nodesetval == NULL)
8708 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8709 else
8710 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8711 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008712#endif
8713}
8714
8715/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008716 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008717 * @ctxt: the XPath Parser context
8718 *
8719 * [3] RelativeLocationPath ::= Step
8720 * | RelativeLocationPath '/' Step
8721 * | AbbreviatedRelativeLocationPath
8722 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8723 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008724 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008725 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008726static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008727xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008728(xmlXPathParserContextPtr ctxt) {
8729 SKIP_BLANKS;
8730 if ((CUR == '/') && (NXT(1) == '/')) {
8731 SKIP(2);
8732 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008733 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8734 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008735 } else if (CUR == '/') {
8736 NEXT;
8737 SKIP_BLANKS;
8738 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008739 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008740 SKIP_BLANKS;
8741 while (CUR == '/') {
8742 if ((CUR == '/') && (NXT(1) == '/')) {
8743 SKIP(2);
8744 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008745 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008746 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008747 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008748 } else if (CUR == '/') {
8749 NEXT;
8750 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008751 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008752 }
8753 SKIP_BLANKS;
8754 }
8755}
8756
8757/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008758 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008759 * @ctxt: the XPath Parser context
8760 *
8761 * [1] LocationPath ::= RelativeLocationPath
8762 * | AbsoluteLocationPath
8763 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8764 * | AbbreviatedAbsoluteLocationPath
8765 * [10] AbbreviatedAbsoluteLocationPath ::=
8766 * '//' RelativeLocationPath
8767 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008768 * Compile a location path
8769 *
Owen Taylor3473f882001-02-23 17:55:21 +00008770 * // is short for /descendant-or-self::node()/. For example,
8771 * //para is short for /descendant-or-self::node()/child::para and
8772 * so will select any para element in the document (even a para element
8773 * that is a document element will be selected by //para since the
8774 * document element node is a child of the root node); div//para is
8775 * short for div/descendant-or-self::node()/child::para and so will
8776 * select all para descendants of div children.
8777 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008778static void
8779xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008780 SKIP_BLANKS;
8781 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008782 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008783 } else {
8784 while (CUR == '/') {
8785 if ((CUR == '/') && (NXT(1) == '/')) {
8786 SKIP(2);
8787 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008788 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8789 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008790 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008791 } else if (CUR == '/') {
8792 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008793 SKIP_BLANKS;
8794 if ((CUR != 0 ) &&
8795 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
8796 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008797 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008798 }
8799 }
8800 }
8801}
8802
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008803/************************************************************************
8804 * *
8805 * XPath precompiled expression evaluation *
8806 * *
8807 ************************************************************************/
8808
Daniel Veillardf06307e2001-07-03 10:35:50 +00008809static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008810xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8811
8812/**
8813 * xmlXPathNodeCollectAndTest:
8814 * @ctxt: the XPath Parser context
8815 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008816 * @first: pointer to the first element in document order
8817 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008818 *
8819 * This is the function implementing a step: based on the current list
8820 * of nodes, it builds up a new list, looking at all nodes under that
8821 * axis and selecting them it also do the predicate filtering
8822 *
8823 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00008824 *
8825 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008826 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008827static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008828xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008829 xmlXPathStepOpPtr op,
8830 xmlNodePtr * first, xmlNodePtr * last)
8831{
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008832 xmlXPathAxisVal axis = op->value;
8833 xmlXPathTestVal test = op->value2;
8834 xmlXPathTypeVal type = op->value3;
8835 const xmlChar *prefix = op->value4;
8836 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008837 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008838
8839#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008840 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008841#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008842 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008843 xmlNodeSetPtr ret, list;
8844 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008845 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00008846 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008847 xmlNodePtr cur = NULL;
8848 xmlXPathObjectPtr obj;
8849 xmlNodeSetPtr nodelist;
8850 xmlNodePtr tmp;
8851
Daniel Veillardf06307e2001-07-03 10:35:50 +00008852 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008853 obj = valuePop(ctxt);
8854 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00008855 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008856 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008857 URI = xmlXPathNsLookup(ctxt->context, prefix);
8858 if (URI == NULL)
8859 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008860 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008861#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008862 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008863#endif
8864 switch (axis) {
8865 case AXIS_ANCESTOR:
8866#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008867 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008868#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008869 first = NULL;
8870 next = xmlXPathNextAncestor;
8871 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008872 case AXIS_ANCESTOR_OR_SELF:
8873#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008874 xmlGenericError(xmlGenericErrorContext,
8875 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008876#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008877 first = NULL;
8878 next = xmlXPathNextAncestorOrSelf;
8879 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008880 case AXIS_ATTRIBUTE:
8881#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008882 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008883#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008884 first = NULL;
8885 last = NULL;
8886 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00008887 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008888 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008889 case AXIS_CHILD:
8890#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008891 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008892#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008893 last = NULL;
8894 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00008895 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008896 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008897 case AXIS_DESCENDANT:
8898#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008899 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008900#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008901 last = NULL;
8902 next = xmlXPathNextDescendant;
8903 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008904 case AXIS_DESCENDANT_OR_SELF:
8905#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008906 xmlGenericError(xmlGenericErrorContext,
8907 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008908#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008909 last = NULL;
8910 next = xmlXPathNextDescendantOrSelf;
8911 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008912 case AXIS_FOLLOWING:
8913#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008914 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008915#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008916 last = NULL;
8917 next = xmlXPathNextFollowing;
8918 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008919 case AXIS_FOLLOWING_SIBLING:
8920#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008921 xmlGenericError(xmlGenericErrorContext,
8922 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008923#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008924 last = NULL;
8925 next = xmlXPathNextFollowingSibling;
8926 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008927 case AXIS_NAMESPACE:
8928#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008929 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008930#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008931 first = NULL;
8932 last = NULL;
8933 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00008934 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008935 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008936 case AXIS_PARENT:
8937#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008938 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008939#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008940 first = NULL;
8941 next = xmlXPathNextParent;
8942 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008943 case AXIS_PRECEDING:
8944#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008945 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008946#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008947 first = NULL;
8948 next = xmlXPathNextPrecedingInternal;
8949 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008950 case AXIS_PRECEDING_SIBLING:
8951#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008952 xmlGenericError(xmlGenericErrorContext,
8953 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008954#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008955 first = NULL;
8956 next = xmlXPathNextPrecedingSibling;
8957 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008958 case AXIS_SELF:
8959#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008960 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008961#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008962 first = NULL;
8963 last = NULL;
8964 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00008965 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008966 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008967 }
8968 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008969 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008970
8971 nodelist = obj->nodesetval;
8972 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008973 xmlXPathFreeObject(obj);
8974 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8975 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008976 }
8977 addNode = xmlXPathNodeSetAddUnique;
8978 ret = NULL;
8979#ifdef DEBUG_STEP
8980 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008981 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008982 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008983 case NODE_TEST_NONE:
8984 xmlGenericError(xmlGenericErrorContext,
8985 " searching for none !!!\n");
8986 break;
8987 case NODE_TEST_TYPE:
8988 xmlGenericError(xmlGenericErrorContext,
8989 " searching for type %d\n", type);
8990 break;
8991 case NODE_TEST_PI:
8992 xmlGenericError(xmlGenericErrorContext,
8993 " searching for PI !!!\n");
8994 break;
8995 case NODE_TEST_ALL:
8996 xmlGenericError(xmlGenericErrorContext,
8997 " searching for *\n");
8998 break;
8999 case NODE_TEST_NS:
9000 xmlGenericError(xmlGenericErrorContext,
9001 " searching for namespace %s\n",
9002 prefix);
9003 break;
9004 case NODE_TEST_NAME:
9005 xmlGenericError(xmlGenericErrorContext,
9006 " searching for name %s\n", name);
9007 if (prefix != NULL)
9008 xmlGenericError(xmlGenericErrorContext,
9009 " with namespace %s\n", prefix);
9010 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009011 }
9012 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9013#endif
9014 /*
9015 * 2.3 Node Tests
9016 * - For the attribute axis, the principal node type is attribute.
9017 * - For the namespace axis, the principal node type is namespace.
9018 * - For other axes, the principal node type is element.
9019 *
9020 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009021 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009022 * select all element children of the context node
9023 */
9024 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009025 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009026 ctxt->context->node = nodelist->nodeTab[i];
9027
Daniel Veillardf06307e2001-07-03 10:35:50 +00009028 cur = NULL;
9029 list = xmlXPathNodeSetCreate(NULL);
9030 do {
9031 cur = next(ctxt, cur);
9032 if (cur == NULL)
9033 break;
9034 if ((first != NULL) && (*first == cur))
9035 break;
9036 if (((t % 256) == 0) &&
9037 (first != NULL) && (*first != NULL) &&
9038 (xmlXPathCmpNodes(*first, cur) >= 0))
9039 break;
9040 if ((last != NULL) && (*last == cur))
9041 break;
9042 if (((t % 256) == 0) &&
9043 (last != NULL) && (*last != NULL) &&
9044 (xmlXPathCmpNodes(cur, *last) >= 0))
9045 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009046 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009047#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009048 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
9049#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009050 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009051 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009052 ctxt->context->node = tmp;
9053 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009054 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009055 if ((cur->type == type) ||
9056 ((type == NODE_TYPE_NODE) &&
9057 ((cur->type == XML_DOCUMENT_NODE) ||
9058 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9059 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00009060 (cur->type == XML_NAMESPACE_DECL) ||
9061 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00009062 (cur->type == XML_PI_NODE) ||
9063 (cur->type == XML_COMMENT_NODE) ||
9064 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00009065 (cur->type == XML_TEXT_NODE))) ||
9066 ((type == NODE_TYPE_TEXT) &&
9067 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009068#ifdef DEBUG_STEP
9069 n++;
9070#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009071 addNode(list, cur);
9072 }
9073 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009074 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009075 if (cur->type == XML_PI_NODE) {
9076 if ((name != NULL) &&
9077 (!xmlStrEqual(name, cur->name)))
9078 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009079#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009080 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009081#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009082 addNode(list, cur);
9083 }
9084 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009085 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009086 if (axis == AXIS_ATTRIBUTE) {
9087 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009088#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009089 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009090#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009091 addNode(list, cur);
9092 }
9093 } else if (axis == AXIS_NAMESPACE) {
9094 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009095#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009096 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009097#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009098 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9099 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009100 }
9101 } else {
9102 if (cur->type == XML_ELEMENT_NODE) {
9103 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009104#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009105 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009106#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009107 addNode(list, cur);
9108 } else if ((cur->ns != NULL) &&
9109 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009110#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009111 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009112#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009113 addNode(list, cur);
9114 }
9115 }
9116 }
9117 break;
9118 case NODE_TEST_NS:{
9119 TODO;
9120 break;
9121 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009122 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009123 switch (cur->type) {
9124 case XML_ELEMENT_NODE:
9125 if (xmlStrEqual(name, cur->name)) {
9126 if (prefix == NULL) {
9127 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009128#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009129 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009130#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009131 addNode(list, cur);
9132 }
9133 } else {
9134 if ((cur->ns != NULL) &&
9135 (xmlStrEqual(URI,
9136 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009137#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009138 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009139#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009140 addNode(list, cur);
9141 }
9142 }
9143 }
9144 break;
9145 case XML_ATTRIBUTE_NODE:{
9146 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009147
Daniel Veillardf06307e2001-07-03 10:35:50 +00009148 if (xmlStrEqual(name, attr->name)) {
9149 if (prefix == NULL) {
9150 if ((attr->ns == NULL) ||
9151 (attr->ns->prefix == NULL)) {
9152#ifdef DEBUG_STEP
9153 n++;
9154#endif
9155 addNode(list,
9156 (xmlNodePtr) attr);
9157 }
9158 } else {
9159 if ((attr->ns != NULL) &&
9160 (xmlStrEqual(URI,
9161 attr->ns->
9162 href))) {
9163#ifdef DEBUG_STEP
9164 n++;
9165#endif
9166 addNode(list,
9167 (xmlNodePtr) attr);
9168 }
9169 }
9170 }
9171 break;
9172 }
9173 case XML_NAMESPACE_DECL:
9174 if (cur->type == XML_NAMESPACE_DECL) {
9175 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009176
Daniel Veillardf06307e2001-07-03 10:35:50 +00009177 if ((ns->prefix != NULL) && (name != NULL)
9178 && (xmlStrEqual(ns->prefix, name))) {
9179#ifdef DEBUG_STEP
9180 n++;
9181#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009182 xmlXPathNodeSetAddNs(list,
9183 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009184 }
9185 }
9186 break;
9187 default:
9188 break;
9189 }
9190 break;
9191 break;
9192 }
9193 } while (cur != NULL);
9194
9195 /*
9196 * If there is some predicate filtering do it now
9197 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009198 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009199 xmlXPathObjectPtr obj2;
9200
9201 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9202 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9203 CHECK_TYPE0(XPATH_NODESET);
9204 obj2 = valuePop(ctxt);
9205 list = obj2->nodesetval;
9206 obj2->nodesetval = NULL;
9207 xmlXPathFreeObject(obj2);
9208 }
9209 if (ret == NULL) {
9210 ret = list;
9211 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009212 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009213 xmlXPathFreeNodeSet(list);
9214 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009215 }
9216 ctxt->context->node = tmp;
9217#ifdef DEBUG_STEP
9218 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009219 "\nExamined %d nodes, found %d nodes at that step\n",
9220 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009221#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009222 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009223 if ((obj->boolval) && (obj->user != NULL)) {
9224 ctxt->value->boolval = 1;
9225 ctxt->value->user = obj->user;
9226 obj->user = NULL;
9227 obj->boolval = 0;
9228 }
9229 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009230 return(t);
9231}
9232
9233/**
9234 * xmlXPathNodeCollectAndTestNth:
9235 * @ctxt: the XPath Parser context
9236 * @op: the XPath precompiled step operation
9237 * @indx: the index to collect
9238 * @first: pointer to the first element in document order
9239 * @last: pointer to the last element in document order
9240 *
9241 * This is the function implementing a step: based on the current list
9242 * of nodes, it builds up a new list, looking at all nodes under that
9243 * axis and selecting them it also do the predicate filtering
9244 *
9245 * Pushes the new NodeSet resulting from the search.
9246 * Returns the number of node traversed
9247 */
9248static int
9249xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9250 xmlXPathStepOpPtr op, int indx,
9251 xmlNodePtr * first, xmlNodePtr * last)
9252{
9253 xmlXPathAxisVal axis = op->value;
9254 xmlXPathTestVal test = op->value2;
9255 xmlXPathTypeVal type = op->value3;
9256 const xmlChar *prefix = op->value4;
9257 const xmlChar *name = op->value5;
9258 const xmlChar *URI = NULL;
9259 int n = 0, t = 0;
9260
9261 int i;
9262 xmlNodeSetPtr list;
9263 xmlXPathTraversalFunction next = NULL;
9264 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9265 xmlNodePtr cur = NULL;
9266 xmlXPathObjectPtr obj;
9267 xmlNodeSetPtr nodelist;
9268 xmlNodePtr tmp;
9269
9270 CHECK_TYPE0(XPATH_NODESET);
9271 obj = valuePop(ctxt);
9272 addNode = xmlXPathNodeSetAdd;
9273 if (prefix != NULL) {
9274 URI = xmlXPathNsLookup(ctxt->context, prefix);
9275 if (URI == NULL)
9276 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9277 }
9278#ifdef DEBUG_STEP_NTH
9279 xmlGenericError(xmlGenericErrorContext, "new step : ");
9280 if (first != NULL) {
9281 if (*first != NULL)
9282 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9283 (*first)->name);
9284 else
9285 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9286 }
9287 if (last != NULL) {
9288 if (*last != NULL)
9289 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9290 (*last)->name);
9291 else
9292 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9293 }
9294#endif
9295 switch (axis) {
9296 case AXIS_ANCESTOR:
9297#ifdef DEBUG_STEP_NTH
9298 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9299#endif
9300 first = NULL;
9301 next = xmlXPathNextAncestor;
9302 break;
9303 case AXIS_ANCESTOR_OR_SELF:
9304#ifdef DEBUG_STEP_NTH
9305 xmlGenericError(xmlGenericErrorContext,
9306 "axis 'ancestors-or-self' ");
9307#endif
9308 first = NULL;
9309 next = xmlXPathNextAncestorOrSelf;
9310 break;
9311 case AXIS_ATTRIBUTE:
9312#ifdef DEBUG_STEP_NTH
9313 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9314#endif
9315 first = NULL;
9316 last = NULL;
9317 next = xmlXPathNextAttribute;
9318 break;
9319 case AXIS_CHILD:
9320#ifdef DEBUG_STEP_NTH
9321 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9322#endif
9323 last = NULL;
9324 next = xmlXPathNextChild;
9325 break;
9326 case AXIS_DESCENDANT:
9327#ifdef DEBUG_STEP_NTH
9328 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9329#endif
9330 last = NULL;
9331 next = xmlXPathNextDescendant;
9332 break;
9333 case AXIS_DESCENDANT_OR_SELF:
9334#ifdef DEBUG_STEP_NTH
9335 xmlGenericError(xmlGenericErrorContext,
9336 "axis 'descendant-or-self' ");
9337#endif
9338 last = NULL;
9339 next = xmlXPathNextDescendantOrSelf;
9340 break;
9341 case AXIS_FOLLOWING:
9342#ifdef DEBUG_STEP_NTH
9343 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9344#endif
9345 last = NULL;
9346 next = xmlXPathNextFollowing;
9347 break;
9348 case AXIS_FOLLOWING_SIBLING:
9349#ifdef DEBUG_STEP_NTH
9350 xmlGenericError(xmlGenericErrorContext,
9351 "axis 'following-siblings' ");
9352#endif
9353 last = NULL;
9354 next = xmlXPathNextFollowingSibling;
9355 break;
9356 case AXIS_NAMESPACE:
9357#ifdef DEBUG_STEP_NTH
9358 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9359#endif
9360 last = NULL;
9361 first = NULL;
9362 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9363 break;
9364 case AXIS_PARENT:
9365#ifdef DEBUG_STEP_NTH
9366 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9367#endif
9368 first = NULL;
9369 next = xmlXPathNextParent;
9370 break;
9371 case AXIS_PRECEDING:
9372#ifdef DEBUG_STEP_NTH
9373 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9374#endif
9375 first = NULL;
9376 next = xmlXPathNextPrecedingInternal;
9377 break;
9378 case AXIS_PRECEDING_SIBLING:
9379#ifdef DEBUG_STEP_NTH
9380 xmlGenericError(xmlGenericErrorContext,
9381 "axis 'preceding-sibling' ");
9382#endif
9383 first = NULL;
9384 next = xmlXPathNextPrecedingSibling;
9385 break;
9386 case AXIS_SELF:
9387#ifdef DEBUG_STEP_NTH
9388 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9389#endif
9390 first = NULL;
9391 last = NULL;
9392 next = xmlXPathNextSelf;
9393 break;
9394 }
9395 if (next == NULL)
9396 return(0);
9397
9398 nodelist = obj->nodesetval;
9399 if (nodelist == NULL) {
9400 xmlXPathFreeObject(obj);
9401 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9402 return(0);
9403 }
9404 addNode = xmlXPathNodeSetAddUnique;
9405#ifdef DEBUG_STEP_NTH
9406 xmlGenericError(xmlGenericErrorContext,
9407 " context contains %d nodes\n", nodelist->nodeNr);
9408 switch (test) {
9409 case NODE_TEST_NONE:
9410 xmlGenericError(xmlGenericErrorContext,
9411 " searching for none !!!\n");
9412 break;
9413 case NODE_TEST_TYPE:
9414 xmlGenericError(xmlGenericErrorContext,
9415 " searching for type %d\n", type);
9416 break;
9417 case NODE_TEST_PI:
9418 xmlGenericError(xmlGenericErrorContext,
9419 " searching for PI !!!\n");
9420 break;
9421 case NODE_TEST_ALL:
9422 xmlGenericError(xmlGenericErrorContext,
9423 " searching for *\n");
9424 break;
9425 case NODE_TEST_NS:
9426 xmlGenericError(xmlGenericErrorContext,
9427 " searching for namespace %s\n",
9428 prefix);
9429 break;
9430 case NODE_TEST_NAME:
9431 xmlGenericError(xmlGenericErrorContext,
9432 " searching for name %s\n", name);
9433 if (prefix != NULL)
9434 xmlGenericError(xmlGenericErrorContext,
9435 " with namespace %s\n", prefix);
9436 break;
9437 }
9438 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9439#endif
9440 /*
9441 * 2.3 Node Tests
9442 * - For the attribute axis, the principal node type is attribute.
9443 * - For the namespace axis, the principal node type is namespace.
9444 * - For other axes, the principal node type is element.
9445 *
9446 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009447 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009448 * select all element children of the context node
9449 */
9450 tmp = ctxt->context->node;
9451 list = xmlXPathNodeSetCreate(NULL);
9452 for (i = 0; i < nodelist->nodeNr; i++) {
9453 ctxt->context->node = nodelist->nodeTab[i];
9454
9455 cur = NULL;
9456 n = 0;
9457 do {
9458 cur = next(ctxt, cur);
9459 if (cur == NULL)
9460 break;
9461 if ((first != NULL) && (*first == cur))
9462 break;
9463 if (((t % 256) == 0) &&
9464 (first != NULL) && (*first != NULL) &&
9465 (xmlXPathCmpNodes(*first, cur) >= 0))
9466 break;
9467 if ((last != NULL) && (*last == cur))
9468 break;
9469 if (((t % 256) == 0) &&
9470 (last != NULL) && (*last != NULL) &&
9471 (xmlXPathCmpNodes(cur, *last) >= 0))
9472 break;
9473 t++;
9474 switch (test) {
9475 case NODE_TEST_NONE:
9476 ctxt->context->node = tmp;
9477 STRANGE return(0);
9478 case NODE_TEST_TYPE:
9479 if ((cur->type == type) ||
9480 ((type == NODE_TYPE_NODE) &&
9481 ((cur->type == XML_DOCUMENT_NODE) ||
9482 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9483 (cur->type == XML_ELEMENT_NODE) ||
9484 (cur->type == XML_PI_NODE) ||
9485 (cur->type == XML_COMMENT_NODE) ||
9486 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +00009487 (cur->type == XML_TEXT_NODE))) ||
9488 ((type == NODE_TYPE_TEXT) &&
9489 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009490 n++;
9491 if (n == indx)
9492 addNode(list, cur);
9493 }
9494 break;
9495 case NODE_TEST_PI:
9496 if (cur->type == XML_PI_NODE) {
9497 if ((name != NULL) &&
9498 (!xmlStrEqual(name, cur->name)))
9499 break;
9500 n++;
9501 if (n == indx)
9502 addNode(list, cur);
9503 }
9504 break;
9505 case NODE_TEST_ALL:
9506 if (axis == AXIS_ATTRIBUTE) {
9507 if (cur->type == XML_ATTRIBUTE_NODE) {
9508 n++;
9509 if (n == indx)
9510 addNode(list, cur);
9511 }
9512 } else if (axis == AXIS_NAMESPACE) {
9513 if (cur->type == XML_NAMESPACE_DECL) {
9514 n++;
9515 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009516 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9517 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009518 }
9519 } else {
9520 if (cur->type == XML_ELEMENT_NODE) {
9521 if (prefix == NULL) {
9522 n++;
9523 if (n == indx)
9524 addNode(list, cur);
9525 } else if ((cur->ns != NULL) &&
9526 (xmlStrEqual(URI, cur->ns->href))) {
9527 n++;
9528 if (n == indx)
9529 addNode(list, cur);
9530 }
9531 }
9532 }
9533 break;
9534 case NODE_TEST_NS:{
9535 TODO;
9536 break;
9537 }
9538 case NODE_TEST_NAME:
9539 switch (cur->type) {
9540 case XML_ELEMENT_NODE:
9541 if (xmlStrEqual(name, cur->name)) {
9542 if (prefix == NULL) {
9543 if (cur->ns == NULL) {
9544 n++;
9545 if (n == indx)
9546 addNode(list, cur);
9547 }
9548 } else {
9549 if ((cur->ns != NULL) &&
9550 (xmlStrEqual(URI,
9551 cur->ns->href))) {
9552 n++;
9553 if (n == indx)
9554 addNode(list, cur);
9555 }
9556 }
9557 }
9558 break;
9559 case XML_ATTRIBUTE_NODE:{
9560 xmlAttrPtr attr = (xmlAttrPtr) cur;
9561
9562 if (xmlStrEqual(name, attr->name)) {
9563 if (prefix == NULL) {
9564 if ((attr->ns == NULL) ||
9565 (attr->ns->prefix == NULL)) {
9566 n++;
9567 if (n == indx)
9568 addNode(list, cur);
9569 }
9570 } else {
9571 if ((attr->ns != NULL) &&
9572 (xmlStrEqual(URI,
9573 attr->ns->
9574 href))) {
9575 n++;
9576 if (n == indx)
9577 addNode(list, cur);
9578 }
9579 }
9580 }
9581 break;
9582 }
9583 case XML_NAMESPACE_DECL:
9584 if (cur->type == XML_NAMESPACE_DECL) {
9585 xmlNsPtr ns = (xmlNsPtr) cur;
9586
9587 if ((ns->prefix != NULL) && (name != NULL)
9588 && (xmlStrEqual(ns->prefix, name))) {
9589 n++;
9590 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009591 xmlXPathNodeSetAddNs(list,
9592 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009593 }
9594 }
9595 break;
9596 default:
9597 break;
9598 }
9599 break;
9600 break;
9601 }
9602 } while (n < indx);
9603 }
9604 ctxt->context->node = tmp;
9605#ifdef DEBUG_STEP_NTH
9606 xmlGenericError(xmlGenericErrorContext,
9607 "\nExamined %d nodes, found %d nodes at that step\n",
9608 t, list->nodeNr);
9609#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009610 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009611 if ((obj->boolval) && (obj->user != NULL)) {
9612 ctxt->value->boolval = 1;
9613 ctxt->value->user = obj->user;
9614 obj->user = NULL;
9615 obj->boolval = 0;
9616 }
9617 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009618 return(t);
9619}
9620
9621/**
9622 * xmlXPathCompOpEvalFirst:
9623 * @ctxt: the XPath parser context with the compiled expression
9624 * @op: an XPath compiled operation
9625 * @first: the first elem found so far
9626 *
9627 * Evaluate the Precompiled XPath operation searching only the first
9628 * element in document order
9629 *
9630 * Returns the number of examined objects.
9631 */
9632static int
9633xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9634 xmlXPathStepOpPtr op, xmlNodePtr * first)
9635{
9636 int total = 0, cur;
9637 xmlXPathCompExprPtr comp;
9638 xmlXPathObjectPtr arg1, arg2;
9639
Daniel Veillard556c6682001-10-06 09:59:51 +00009640 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009641 comp = ctxt->comp;
9642 switch (op->op) {
9643 case XPATH_OP_END:
9644 return (0);
9645 case XPATH_OP_UNION:
9646 total =
9647 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9648 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009649 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009650 if ((ctxt->value != NULL)
9651 && (ctxt->value->type == XPATH_NODESET)
9652 && (ctxt->value->nodesetval != NULL)
9653 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9654 /*
9655 * limit tree traversing to first node in the result
9656 */
9657 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9658 *first = ctxt->value->nodesetval->nodeTab[0];
9659 }
9660 cur =
9661 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9662 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009663 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009664 CHECK_TYPE0(XPATH_NODESET);
9665 arg2 = valuePop(ctxt);
9666
9667 CHECK_TYPE0(XPATH_NODESET);
9668 arg1 = valuePop(ctxt);
9669
9670 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9671 arg2->nodesetval);
9672 valuePush(ctxt, arg1);
9673 xmlXPathFreeObject(arg2);
9674 /* optimizer */
9675 if (total > cur)
9676 xmlXPathCompSwap(op);
9677 return (total + cur);
9678 case XPATH_OP_ROOT:
9679 xmlXPathRoot(ctxt);
9680 return (0);
9681 case XPATH_OP_NODE:
9682 if (op->ch1 != -1)
9683 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009684 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009685 if (op->ch2 != -1)
9686 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009687 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009688 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9689 return (total);
9690 case XPATH_OP_RESET:
9691 if (op->ch1 != -1)
9692 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009693 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009694 if (op->ch2 != -1)
9695 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009696 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009697 ctxt->context->node = NULL;
9698 return (total);
9699 case XPATH_OP_COLLECT:{
9700 if (op->ch1 == -1)
9701 return (total);
9702
9703 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009704 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009705
9706 /*
9707 * Optimization for [n] selection where n is a number
9708 */
9709 if ((op->ch2 != -1) &&
9710 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9711 (comp->steps[op->ch2].ch1 == -1) &&
9712 (comp->steps[op->ch2].ch2 != -1) &&
9713 (comp->steps[comp->steps[op->ch2].ch2].op ==
9714 XPATH_OP_VALUE)) {
9715 xmlXPathObjectPtr val;
9716
9717 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9718 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9719 int indx = (int) val->floatval;
9720
9721 if (val->floatval == (float) indx) {
9722 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9723 first, NULL);
9724 return (total);
9725 }
9726 }
9727 }
9728 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9729 return (total);
9730 }
9731 case XPATH_OP_VALUE:
9732 valuePush(ctxt,
9733 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9734 return (0);
9735 case XPATH_OP_SORT:
9736 if (op->ch1 != -1)
9737 total +=
9738 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9739 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009740 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009741 if ((ctxt->value != NULL)
9742 && (ctxt->value->type == XPATH_NODESET)
9743 && (ctxt->value->nodesetval != NULL))
9744 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9745 return (total);
9746 default:
9747 return (xmlXPathCompOpEval(ctxt, op));
9748 }
9749}
9750
9751/**
9752 * xmlXPathCompOpEvalLast:
9753 * @ctxt: the XPath parser context with the compiled expression
9754 * @op: an XPath compiled operation
9755 * @last: the last elem found so far
9756 *
9757 * Evaluate the Precompiled XPath operation searching only the last
9758 * element in document order
9759 *
9760 * Returns the number of node traversed
9761 */
9762static int
9763xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9764 xmlNodePtr * last)
9765{
9766 int total = 0, cur;
9767 xmlXPathCompExprPtr comp;
9768 xmlXPathObjectPtr arg1, arg2;
9769
Daniel Veillard556c6682001-10-06 09:59:51 +00009770 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009771 comp = ctxt->comp;
9772 switch (op->op) {
9773 case XPATH_OP_END:
9774 return (0);
9775 case XPATH_OP_UNION:
9776 total =
9777 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009778 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009779 if ((ctxt->value != NULL)
9780 && (ctxt->value->type == XPATH_NODESET)
9781 && (ctxt->value->nodesetval != NULL)
9782 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9783 /*
9784 * limit tree traversing to first node in the result
9785 */
9786 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9787 *last =
9788 ctxt->value->nodesetval->nodeTab[ctxt->value->
9789 nodesetval->nodeNr -
9790 1];
9791 }
9792 cur =
9793 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009794 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009795 if ((ctxt->value != NULL)
9796 && (ctxt->value->type == XPATH_NODESET)
9797 && (ctxt->value->nodesetval != NULL)
9798 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9799 }
9800 CHECK_TYPE0(XPATH_NODESET);
9801 arg2 = valuePop(ctxt);
9802
9803 CHECK_TYPE0(XPATH_NODESET);
9804 arg1 = valuePop(ctxt);
9805
9806 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9807 arg2->nodesetval);
9808 valuePush(ctxt, arg1);
9809 xmlXPathFreeObject(arg2);
9810 /* optimizer */
9811 if (total > cur)
9812 xmlXPathCompSwap(op);
9813 return (total + cur);
9814 case XPATH_OP_ROOT:
9815 xmlXPathRoot(ctxt);
9816 return (0);
9817 case XPATH_OP_NODE:
9818 if (op->ch1 != -1)
9819 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009820 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009821 if (op->ch2 != -1)
9822 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009823 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009824 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9825 return (total);
9826 case XPATH_OP_RESET:
9827 if (op->ch1 != -1)
9828 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009829 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009830 if (op->ch2 != -1)
9831 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009832 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009833 ctxt->context->node = NULL;
9834 return (total);
9835 case XPATH_OP_COLLECT:{
9836 if (op->ch1 == -1)
9837 return (0);
9838
9839 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009840 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009841
9842 /*
9843 * Optimization for [n] selection where n is a number
9844 */
9845 if ((op->ch2 != -1) &&
9846 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9847 (comp->steps[op->ch2].ch1 == -1) &&
9848 (comp->steps[op->ch2].ch2 != -1) &&
9849 (comp->steps[comp->steps[op->ch2].ch2].op ==
9850 XPATH_OP_VALUE)) {
9851 xmlXPathObjectPtr val;
9852
9853 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9854 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9855 int indx = (int) val->floatval;
9856
9857 if (val->floatval == (float) indx) {
9858 total +=
9859 xmlXPathNodeCollectAndTestNth(ctxt, op,
9860 indx, NULL,
9861 last);
9862 return (total);
9863 }
9864 }
9865 }
9866 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9867 return (total);
9868 }
9869 case XPATH_OP_VALUE:
9870 valuePush(ctxt,
9871 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9872 return (0);
9873 case XPATH_OP_SORT:
9874 if (op->ch1 != -1)
9875 total +=
9876 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9877 last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009878 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009879 if ((ctxt->value != NULL)
9880 && (ctxt->value->type == XPATH_NODESET)
9881 && (ctxt->value->nodesetval != NULL))
9882 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9883 return (total);
9884 default:
9885 return (xmlXPathCompOpEval(ctxt, op));
9886 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009887}
9888
Owen Taylor3473f882001-02-23 17:55:21 +00009889/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009890 * xmlXPathCompOpEval:
9891 * @ctxt: the XPath parser context with the compiled expression
9892 * @op: an XPath compiled operation
9893 *
9894 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009895 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009896 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009897static int
9898xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9899{
9900 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009901 int equal, ret;
9902 xmlXPathCompExprPtr comp;
9903 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009904 xmlNodePtr bak;
9905 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +00009906 int pp;
William M. Brack692092b2002-06-28 15:01:24 +00009907 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009908
Daniel Veillard556c6682001-10-06 09:59:51 +00009909 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009910 comp = ctxt->comp;
9911 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009912 case XPATH_OP_END:
9913 return (0);
9914 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009915 bakd = ctxt->context->doc;
9916 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009917 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009918 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009919 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009920 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009921 xmlXPathBooleanFunction(ctxt, 1);
9922 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9923 return (total);
9924 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009925 ctxt->context->doc = bakd;
9926 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009927 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009928 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009929 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009930 if (ctxt->error) {
9931 xmlXPathFreeObject(arg2);
9932 return(0);
9933 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009934 xmlXPathBooleanFunction(ctxt, 1);
9935 arg1 = valuePop(ctxt);
9936 arg1->boolval &= arg2->boolval;
9937 valuePush(ctxt, arg1);
9938 xmlXPathFreeObject(arg2);
9939 return (total);
9940 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009941 bakd = ctxt->context->doc;
9942 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009943 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009944 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009945 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009946 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009947 xmlXPathBooleanFunction(ctxt, 1);
9948 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9949 return (total);
9950 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009951 ctxt->context->doc = bakd;
9952 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009953 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009954 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009955 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009956 if (ctxt->error) {
9957 xmlXPathFreeObject(arg2);
9958 return(0);
9959 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009960 xmlXPathBooleanFunction(ctxt, 1);
9961 arg1 = valuePop(ctxt);
9962 arg1->boolval |= arg2->boolval;
9963 valuePush(ctxt, arg1);
9964 xmlXPathFreeObject(arg2);
9965 return (total);
9966 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009967 bakd = ctxt->context->doc;
9968 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009969 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009970 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009971 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009972 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009973 ctxt->context->doc = bakd;
9974 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009975 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009976 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009977 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009978 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +00009979 if (op->value)
9980 equal = xmlXPathEqualValues(ctxt);
9981 else
9982 equal = xmlXPathNotEqualValues(ctxt);
9983 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +00009984 return (total);
9985 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009986 bakd = ctxt->context->doc;
9987 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009988 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009989 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009990 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009991 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009992 ctxt->context->doc = bakd;
9993 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009994 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009995 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009996 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009997 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009998 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
9999 valuePush(ctxt, xmlXPathNewBoolean(ret));
10000 return (total);
10001 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010002 bakd = ctxt->context->doc;
10003 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010004 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010005 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010006 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010007 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010008 if (op->ch2 != -1) {
10009 ctxt->context->doc = bakd;
10010 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010011 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010012 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010013 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010014 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010015 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010016 if (op->value == 0)
10017 xmlXPathSubValues(ctxt);
10018 else if (op->value == 1)
10019 xmlXPathAddValues(ctxt);
10020 else if (op->value == 2)
10021 xmlXPathValueFlipSign(ctxt);
10022 else if (op->value == 3) {
10023 CAST_TO_NUMBER;
10024 CHECK_TYPE0(XPATH_NUMBER);
10025 }
10026 return (total);
10027 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010028 bakd = ctxt->context->doc;
10029 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010030 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010031 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010032 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010033 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010034 ctxt->context->doc = bakd;
10035 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010036 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010037 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010038 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010039 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010040 if (op->value == 0)
10041 xmlXPathMultValues(ctxt);
10042 else if (op->value == 1)
10043 xmlXPathDivValues(ctxt);
10044 else if (op->value == 2)
10045 xmlXPathModValues(ctxt);
10046 return (total);
10047 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010048 bakd = ctxt->context->doc;
10049 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010050 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010051 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010052 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010053 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010054 ctxt->context->doc = bakd;
10055 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010056 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010057 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010058 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010059 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010060 CHECK_TYPE0(XPATH_NODESET);
10061 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010062
Daniel Veillardf06307e2001-07-03 10:35:50 +000010063 CHECK_TYPE0(XPATH_NODESET);
10064 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010065
Daniel Veillardf06307e2001-07-03 10:35:50 +000010066 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10067 arg2->nodesetval);
10068 valuePush(ctxt, arg1);
10069 xmlXPathFreeObject(arg2);
10070 return (total);
10071 case XPATH_OP_ROOT:
10072 xmlXPathRoot(ctxt);
10073 return (total);
10074 case XPATH_OP_NODE:
10075 if (op->ch1 != -1)
10076 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010077 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010078 if (op->ch2 != -1)
10079 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010080 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010081 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10082 return (total);
10083 case XPATH_OP_RESET:
10084 if (op->ch1 != -1)
10085 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010086 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010087 if (op->ch2 != -1)
10088 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010089 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010090 ctxt->context->node = NULL;
10091 return (total);
10092 case XPATH_OP_COLLECT:{
10093 if (op->ch1 == -1)
10094 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010095
Daniel Veillardf06307e2001-07-03 10:35:50 +000010096 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010097 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010098
Daniel Veillardf06307e2001-07-03 10:35:50 +000010099 /*
10100 * Optimization for [n] selection where n is a number
10101 */
10102 if ((op->ch2 != -1) &&
10103 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10104 (comp->steps[op->ch2].ch1 == -1) &&
10105 (comp->steps[op->ch2].ch2 != -1) &&
10106 (comp->steps[comp->steps[op->ch2].ch2].op ==
10107 XPATH_OP_VALUE)) {
10108 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +000010109
Daniel Veillardf06307e2001-07-03 10:35:50 +000010110 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10111 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10112 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010113
Daniel Veillardf06307e2001-07-03 10:35:50 +000010114 if (val->floatval == (float) indx) {
10115 total +=
10116 xmlXPathNodeCollectAndTestNth(ctxt, op,
10117 indx, NULL,
10118 NULL);
10119 return (total);
10120 }
10121 }
10122 }
10123 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
10124 return (total);
10125 }
10126 case XPATH_OP_VALUE:
10127 valuePush(ctxt,
10128 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10129 return (total);
10130 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000010131 xmlXPathObjectPtr val;
10132
Daniel Veillardf06307e2001-07-03 10:35:50 +000010133 if (op->ch1 != -1)
10134 total +=
10135 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010136 if (op->value5 == NULL) {
10137 val = xmlXPathVariableLookup(ctxt->context, op->value4);
10138 if (val == NULL) {
10139 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10140 return(0);
10141 }
10142 valuePush(ctxt, val);
10143 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010144 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010145
Daniel Veillardf06307e2001-07-03 10:35:50 +000010146 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10147 if (URI == NULL) {
10148 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010149 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010150 op->value4, op->value5);
10151 return (total);
10152 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010153 val = xmlXPathVariableLookupNS(ctxt->context,
10154 op->value4, URI);
10155 if (val == NULL) {
10156 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10157 return(0);
10158 }
10159 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010160 }
10161 return (total);
10162 }
10163 case XPATH_OP_FUNCTION:{
10164 xmlXPathFunction func;
10165 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000010166 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010167
10168 if (op->ch1 != -1)
10169 total +=
10170 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010171 if (ctxt->valueNr < op->value) {
10172 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010173 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010174 ctxt->error = XPATH_INVALID_OPERAND;
10175 return (total);
10176 }
10177 for (i = 0; i < op->value; i++)
10178 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10179 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010180 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010181 ctxt->error = XPATH_INVALID_OPERAND;
10182 return (total);
10183 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010184 if (op->cache != NULL)
10185 func = (xmlXPathFunction) op->cache;
10186 else {
10187 const xmlChar *URI = NULL;
10188
10189 if (op->value5 == NULL)
10190 func =
10191 xmlXPathFunctionLookup(ctxt->context,
10192 op->value4);
10193 else {
10194 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10195 if (URI == NULL) {
10196 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010197 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010198 op->value4, op->value5);
10199 return (total);
10200 }
10201 func = xmlXPathFunctionLookupNS(ctxt->context,
10202 op->value4, URI);
10203 }
10204 if (func == NULL) {
10205 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010206 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010207 op->value4);
10208 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010209 }
10210 op->cache = (void *) func;
10211 op->cacheURI = (void *) URI;
10212 }
10213 oldFunc = ctxt->context->function;
10214 oldFuncURI = ctxt->context->functionURI;
10215 ctxt->context->function = op->value4;
10216 ctxt->context->functionURI = op->cacheURI;
10217 func(ctxt, op->value);
10218 ctxt->context->function = oldFunc;
10219 ctxt->context->functionURI = oldFuncURI;
10220 return (total);
10221 }
10222 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000010223 bakd = ctxt->context->doc;
10224 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010225 if (op->ch1 != -1)
10226 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010227 ctxt->context->doc = bakd;
10228 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010229 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010230 if (op->ch2 != -1)
10231 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010232 ctxt->context->doc = bakd;
10233 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010234 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010235 return (total);
10236 case XPATH_OP_PREDICATE:
10237 case XPATH_OP_FILTER:{
10238 xmlXPathObjectPtr res;
10239 xmlXPathObjectPtr obj, tmp;
10240 xmlNodeSetPtr newset = NULL;
10241 xmlNodeSetPtr oldset;
10242 xmlNodePtr oldnode;
10243 int i;
10244
10245 /*
10246 * Optimization for ()[1] selection i.e. the first elem
10247 */
10248 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10249 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10250 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10251 xmlXPathObjectPtr val;
10252
10253 val = comp->steps[op->ch2].value4;
10254 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10255 (val->floatval == 1.0)) {
10256 xmlNodePtr first = NULL;
10257
10258 total +=
10259 xmlXPathCompOpEvalFirst(ctxt,
10260 &comp->steps[op->ch1],
10261 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010262 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010263 /*
10264 * The nodeset should be in document order,
10265 * Keep only the first value
10266 */
10267 if ((ctxt->value != NULL) &&
10268 (ctxt->value->type == XPATH_NODESET) &&
10269 (ctxt->value->nodesetval != NULL) &&
10270 (ctxt->value->nodesetval->nodeNr > 1))
10271 ctxt->value->nodesetval->nodeNr = 1;
10272 return (total);
10273 }
10274 }
10275 /*
10276 * Optimization for ()[last()] selection i.e. the last elem
10277 */
10278 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10279 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10280 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10281 int f = comp->steps[op->ch2].ch1;
10282
10283 if ((f != -1) &&
10284 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10285 (comp->steps[f].value5 == NULL) &&
10286 (comp->steps[f].value == 0) &&
10287 (comp->steps[f].value4 != NULL) &&
10288 (xmlStrEqual
10289 (comp->steps[f].value4, BAD_CAST "last"))) {
10290 xmlNodePtr last = NULL;
10291
10292 total +=
10293 xmlXPathCompOpEvalLast(ctxt,
10294 &comp->steps[op->ch1],
10295 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010296 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010297 /*
10298 * The nodeset should be in document order,
10299 * Keep only the last value
10300 */
10301 if ((ctxt->value != NULL) &&
10302 (ctxt->value->type == XPATH_NODESET) &&
10303 (ctxt->value->nodesetval != NULL) &&
10304 (ctxt->value->nodesetval->nodeTab != NULL) &&
10305 (ctxt->value->nodesetval->nodeNr > 1)) {
10306 ctxt->value->nodesetval->nodeTab[0] =
10307 ctxt->value->nodesetval->nodeTab[ctxt->
10308 value->
10309 nodesetval->
10310 nodeNr -
10311 1];
10312 ctxt->value->nodesetval->nodeNr = 1;
10313 }
10314 return (total);
10315 }
10316 }
10317
10318 if (op->ch1 != -1)
10319 total +=
10320 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010321 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010322 if (op->ch2 == -1)
10323 return (total);
10324 if (ctxt->value == NULL)
10325 return (total);
10326
10327 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010328
10329#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010330 /*
10331 * Hum are we filtering the result of an XPointer expression
10332 */
10333 if (ctxt->value->type == XPATH_LOCATIONSET) {
10334 xmlLocationSetPtr newlocset = NULL;
10335 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010336
Daniel Veillardf06307e2001-07-03 10:35:50 +000010337 /*
10338 * Extract the old locset, and then evaluate the result of the
10339 * expression for all the element in the locset. use it to grow
10340 * up a new locset.
10341 */
10342 CHECK_TYPE0(XPATH_LOCATIONSET);
10343 obj = valuePop(ctxt);
10344 oldlocset = obj->user;
10345 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010346
Daniel Veillardf06307e2001-07-03 10:35:50 +000010347 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10348 ctxt->context->contextSize = 0;
10349 ctxt->context->proximityPosition = 0;
10350 if (op->ch2 != -1)
10351 total +=
10352 xmlXPathCompOpEval(ctxt,
10353 &comp->steps[op->ch2]);
10354 res = valuePop(ctxt);
10355 if (res != NULL)
10356 xmlXPathFreeObject(res);
10357 valuePush(ctxt, obj);
10358 CHECK_ERROR0;
10359 return (total);
10360 }
10361 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010362
Daniel Veillardf06307e2001-07-03 10:35:50 +000010363 for (i = 0; i < oldlocset->locNr; i++) {
10364 /*
10365 * Run the evaluation with a node list made of a
10366 * single item in the nodelocset.
10367 */
10368 ctxt->context->node = oldlocset->locTab[i]->user;
10369 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10370 valuePush(ctxt, tmp);
10371 ctxt->context->contextSize = oldlocset->locNr;
10372 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010373
Daniel Veillardf06307e2001-07-03 10:35:50 +000010374 if (op->ch2 != -1)
10375 total +=
10376 xmlXPathCompOpEval(ctxt,
10377 &comp->steps[op->ch2]);
10378 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010379
Daniel Veillardf06307e2001-07-03 10:35:50 +000010380 /*
10381 * The result of the evaluation need to be tested to
10382 * decided whether the filter succeeded or not
10383 */
10384 res = valuePop(ctxt);
10385 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10386 xmlXPtrLocationSetAdd(newlocset,
10387 xmlXPathObjectCopy
10388 (oldlocset->locTab[i]));
10389 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010390
Daniel Veillardf06307e2001-07-03 10:35:50 +000010391 /*
10392 * Cleanup
10393 */
10394 if (res != NULL)
10395 xmlXPathFreeObject(res);
10396 if (ctxt->value == tmp) {
10397 res = valuePop(ctxt);
10398 xmlXPathFreeObject(res);
10399 }
10400
10401 ctxt->context->node = NULL;
10402 }
10403
10404 /*
10405 * The result is used as the new evaluation locset.
10406 */
10407 xmlXPathFreeObject(obj);
10408 ctxt->context->node = NULL;
10409 ctxt->context->contextSize = -1;
10410 ctxt->context->proximityPosition = -1;
10411 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10412 ctxt->context->node = oldnode;
10413 return (total);
10414 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010415#endif /* LIBXML_XPTR_ENABLED */
10416
Daniel Veillardf06307e2001-07-03 10:35:50 +000010417 /*
10418 * Extract the old set, and then evaluate the result of the
10419 * expression for all the element in the set. use it to grow
10420 * up a new set.
10421 */
10422 CHECK_TYPE0(XPATH_NODESET);
10423 obj = valuePop(ctxt);
10424 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010425
Daniel Veillardf06307e2001-07-03 10:35:50 +000010426 oldnode = ctxt->context->node;
10427 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010428
Daniel Veillardf06307e2001-07-03 10:35:50 +000010429 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10430 ctxt->context->contextSize = 0;
10431 ctxt->context->proximityPosition = 0;
10432 if (op->ch2 != -1)
10433 total +=
10434 xmlXPathCompOpEval(ctxt,
10435 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010436 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010437 res = valuePop(ctxt);
10438 if (res != NULL)
10439 xmlXPathFreeObject(res);
10440 valuePush(ctxt, obj);
10441 ctxt->context->node = oldnode;
10442 CHECK_ERROR0;
10443 } else {
10444 /*
10445 * Initialize the new set.
10446 */
10447 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010448
Daniel Veillardf06307e2001-07-03 10:35:50 +000010449 for (i = 0; i < oldset->nodeNr; i++) {
10450 /*
10451 * Run the evaluation with a node list made of
10452 * a single item in the nodeset.
10453 */
10454 ctxt->context->node = oldset->nodeTab[i];
10455 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10456 valuePush(ctxt, tmp);
10457 ctxt->context->contextSize = oldset->nodeNr;
10458 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010459
Daniel Veillardf06307e2001-07-03 10:35:50 +000010460 if (op->ch2 != -1)
10461 total +=
10462 xmlXPathCompOpEval(ctxt,
10463 &comp->steps[op->ch2]);
10464 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010465
Daniel Veillardf06307e2001-07-03 10:35:50 +000010466 /*
10467 * The result of the evaluation need to be tested to
10468 * decided whether the filter succeeded or not
10469 */
10470 res = valuePop(ctxt);
10471 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10472 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10473 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010474
Daniel Veillardf06307e2001-07-03 10:35:50 +000010475 /*
10476 * Cleanup
10477 */
10478 if (res != NULL)
10479 xmlXPathFreeObject(res);
10480 if (ctxt->value == tmp) {
10481 res = valuePop(ctxt);
10482 xmlXPathFreeObject(res);
10483 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010484
Daniel Veillardf06307e2001-07-03 10:35:50 +000010485 ctxt->context->node = NULL;
10486 }
10487
10488 /*
10489 * The result is used as the new evaluation set.
10490 */
10491 xmlXPathFreeObject(obj);
10492 ctxt->context->node = NULL;
10493 ctxt->context->contextSize = -1;
10494 ctxt->context->proximityPosition = -1;
10495 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10496 }
10497 ctxt->context->node = oldnode;
10498 return (total);
10499 }
10500 case XPATH_OP_SORT:
10501 if (op->ch1 != -1)
10502 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010503 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010504 if ((ctxt->value != NULL) &&
10505 (ctxt->value->type == XPATH_NODESET) &&
10506 (ctxt->value->nodesetval != NULL))
10507 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10508 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010509#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010510 case XPATH_OP_RANGETO:{
10511 xmlXPathObjectPtr range;
10512 xmlXPathObjectPtr res, obj;
10513 xmlXPathObjectPtr tmp;
10514 xmlLocationSetPtr newset = NULL;
10515 xmlNodeSetPtr oldset;
10516 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010517
Daniel Veillardf06307e2001-07-03 10:35:50 +000010518 if (op->ch1 != -1)
10519 total +=
10520 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10521 if (op->ch2 == -1)
10522 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010523
Daniel Veillardf06307e2001-07-03 10:35:50 +000010524 CHECK_TYPE0(XPATH_NODESET);
10525 obj = valuePop(ctxt);
10526 oldset = obj->nodesetval;
10527 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010528
Daniel Veillardf06307e2001-07-03 10:35:50 +000010529 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010530
Daniel Veillardf06307e2001-07-03 10:35:50 +000010531 if (oldset != NULL) {
10532 for (i = 0; i < oldset->nodeNr; i++) {
10533 /*
10534 * Run the evaluation with a node list made of a single item
10535 * in the nodeset.
10536 */
10537 ctxt->context->node = oldset->nodeTab[i];
10538 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10539 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010540
Daniel Veillardf06307e2001-07-03 10:35:50 +000010541 if (op->ch2 != -1)
10542 total +=
10543 xmlXPathCompOpEval(ctxt,
10544 &comp->steps[op->ch2]);
10545 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010546
Daniel Veillardf06307e2001-07-03 10:35:50 +000010547 /*
10548 * The result of the evaluation need to be tested to
10549 * decided whether the filter succeeded or not
10550 */
10551 res = valuePop(ctxt);
10552 range =
10553 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10554 res);
10555 if (range != NULL) {
10556 xmlXPtrLocationSetAdd(newset, range);
10557 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010558
Daniel Veillardf06307e2001-07-03 10:35:50 +000010559 /*
10560 * Cleanup
10561 */
10562 if (res != NULL)
10563 xmlXPathFreeObject(res);
10564 if (ctxt->value == tmp) {
10565 res = valuePop(ctxt);
10566 xmlXPathFreeObject(res);
10567 }
10568
10569 ctxt->context->node = NULL;
10570 }
10571 }
10572
10573 /*
10574 * The result is used as the new evaluation set.
10575 */
10576 xmlXPathFreeObject(obj);
10577 ctxt->context->node = NULL;
10578 ctxt->context->contextSize = -1;
10579 ctxt->context->proximityPosition = -1;
10580 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
10581 return (total);
10582 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010583#endif /* LIBXML_XPTR_ENABLED */
10584 }
10585 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010586 "XPath: unknown precompiled operation %d\n", op->op);
10587 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010588}
10589
10590/**
10591 * xmlXPathRunEval:
10592 * @ctxt: the XPath parser context with the compiled expression
10593 *
10594 * Evaluate the Precompiled XPath expression in the given context.
10595 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010596static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010597xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10598 xmlXPathCompExprPtr comp;
10599
10600 if ((ctxt == NULL) || (ctxt->comp == NULL))
10601 return;
10602
10603 if (ctxt->valueTab == NULL) {
10604 /* Allocate the value stack */
10605 ctxt->valueTab = (xmlXPathObjectPtr *)
10606 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10607 if (ctxt->valueTab == NULL) {
10608 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010609 }
10610 ctxt->valueNr = 0;
10611 ctxt->valueMax = 10;
10612 ctxt->value = NULL;
10613 }
10614 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000010615 if(comp->last < 0) {
10616 xmlGenericError(xmlGenericErrorContext,
10617 "xmlXPathRunEval: last is less than zero\n");
10618 return;
10619 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010620 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10621}
10622
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010623/************************************************************************
10624 * *
10625 * Public interfaces *
10626 * *
10627 ************************************************************************/
10628
10629/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010630 * xmlXPathEvalPredicate:
10631 * @ctxt: the XPath context
10632 * @res: the Predicate Expression evaluation result
10633 *
10634 * Evaluate a predicate result for the current node.
10635 * A PredicateExpr is evaluated by evaluating the Expr and converting
10636 * the result to a boolean. If the result is a number, the result will
10637 * be converted to true if the number is equal to the position of the
10638 * context node in the context node list (as returned by the position
10639 * function) and will be converted to false otherwise; if the result
10640 * is not a number, then the result will be converted as if by a call
10641 * to the boolean function.
10642 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010643 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010644 */
10645int
10646xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
10647 if (res == NULL) return(0);
10648 switch (res->type) {
10649 case XPATH_BOOLEAN:
10650 return(res->boolval);
10651 case XPATH_NUMBER:
10652 return(res->floatval == ctxt->proximityPosition);
10653 case XPATH_NODESET:
10654 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010655 if (res->nodesetval == NULL)
10656 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010657 return(res->nodesetval->nodeNr != 0);
10658 case XPATH_STRING:
10659 return((res->stringval != NULL) &&
10660 (xmlStrlen(res->stringval) != 0));
10661 default:
10662 STRANGE
10663 }
10664 return(0);
10665}
10666
10667/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010668 * xmlXPathEvaluatePredicateResult:
10669 * @ctxt: the XPath Parser context
10670 * @res: the Predicate Expression evaluation result
10671 *
10672 * Evaluate a predicate result for the current node.
10673 * A PredicateExpr is evaluated by evaluating the Expr and converting
10674 * the result to a boolean. If the result is a number, the result will
10675 * be converted to true if the number is equal to the position of the
10676 * context node in the context node list (as returned by the position
10677 * function) and will be converted to false otherwise; if the result
10678 * is not a number, then the result will be converted as if by a call
10679 * to the boolean function.
10680 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010681 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010682 */
10683int
10684xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10685 xmlXPathObjectPtr res) {
10686 if (res == NULL) return(0);
10687 switch (res->type) {
10688 case XPATH_BOOLEAN:
10689 return(res->boolval);
10690 case XPATH_NUMBER:
10691 return(res->floatval == ctxt->context->proximityPosition);
10692 case XPATH_NODESET:
10693 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000010694 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000010695 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010696 return(res->nodesetval->nodeNr != 0);
10697 case XPATH_STRING:
10698 return((res->stringval != NULL) &&
10699 (xmlStrlen(res->stringval) != 0));
10700 default:
10701 STRANGE
10702 }
10703 return(0);
10704}
10705
10706/**
10707 * xmlXPathCompile:
10708 * @str: the XPath expression
10709 *
10710 * Compile an XPath expression
10711 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000010712 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010713 * the caller has to free the object.
10714 */
10715xmlXPathCompExprPtr
10716xmlXPathCompile(const xmlChar *str) {
10717 xmlXPathParserContextPtr ctxt;
10718 xmlXPathCompExprPtr comp;
10719
10720 xmlXPathInit();
10721
10722 ctxt = xmlXPathNewParserContext(str, NULL);
10723 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010724
Daniel Veillard40af6492001-04-22 08:50:55 +000010725 if (*ctxt->cur != 0) {
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010726 /*
10727 * aleksey: in some cases this line prints *second* error message
10728 * (see bug #78858) and probably this should be fixed.
10729 * However, we are not sure that all error messages are printed
10730 * out in other places. It's not critical so we leave it as-is for now
10731 */
Daniel Veillard40af6492001-04-22 08:50:55 +000010732 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10733 comp = NULL;
10734 } else {
10735 comp = ctxt->comp;
10736 ctxt->comp = NULL;
10737 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010738 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010739 if (comp != NULL) {
Daniel Veillardceb09b92002-10-04 11:46:37 +000010740 comp->expr = xmlStrdup(str);
10741#ifdef DEBUG_EVAL_COUNTS
Daniel Veillardf06307e2001-07-03 10:35:50 +000010742 comp->string = xmlStrdup(str);
10743 comp->nb = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010744#endif
Daniel Veillardceb09b92002-10-04 11:46:37 +000010745 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010746 return(comp);
10747}
10748
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010749/**
10750 * xmlXPathCompiledEval:
10751 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000010752 * @ctx: the XPath context
10753 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010754 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000010755 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010756 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000010757 * the caller has to free the object.
10758 */
10759xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010760xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000010761 xmlXPathParserContextPtr ctxt;
10762 xmlXPathObjectPtr res, tmp, init = NULL;
10763 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000010764#ifndef LIBXML_THREAD_ENABLED
10765 static int reentance = 0;
10766#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010767
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010768 if ((comp == NULL) || (ctx == NULL))
10769 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010770 xmlXPathInit();
10771
10772 CHECK_CONTEXT(ctx)
10773
Daniel Veillard81463942001-10-16 12:34:39 +000010774#ifndef LIBXML_THREAD_ENABLED
10775 reentance++;
10776 if (reentance > 1)
10777 xmlXPathDisableOptimizer = 1;
10778#endif
10779
Daniel Veillardf06307e2001-07-03 10:35:50 +000010780#ifdef DEBUG_EVAL_COUNTS
10781 comp->nb++;
10782 if ((comp->string != NULL) && (comp->nb > 100)) {
10783 fprintf(stderr, "100 x %s\n", comp->string);
10784 comp->nb = 0;
10785 }
10786#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010787 ctxt = xmlXPathCompParserContext(comp, ctx);
10788 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010789
10790 if (ctxt->value == NULL) {
10791 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010792 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000010793 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000010794 } else {
10795 res = valuePop(ctxt);
10796 }
10797
Daniel Veillardf06307e2001-07-03 10:35:50 +000010798
Owen Taylor3473f882001-02-23 17:55:21 +000010799 do {
10800 tmp = valuePop(ctxt);
10801 if (tmp != NULL) {
10802 if (tmp != init)
10803 stack++;
10804 xmlXPathFreeObject(tmp);
10805 }
10806 } while (tmp != NULL);
10807 if ((stack != 0) && (res != NULL)) {
10808 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010809 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000010810 stack);
10811 }
10812 if (ctxt->error != XPATH_EXPRESSION_OK) {
10813 xmlXPathFreeObject(res);
10814 res = NULL;
10815 }
10816
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010817
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010818 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010819 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000010820#ifndef LIBXML_THREAD_ENABLED
10821 reentance--;
10822#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010823 return(res);
10824}
10825
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010826/**
10827 * xmlXPathEvalExpr:
10828 * @ctxt: the XPath Parser context
10829 *
10830 * Parse and evaluate an XPath expression in the given context,
10831 * then push the result on the context stack
10832 */
10833void
10834xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
10835 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010836 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010837 xmlXPathRunEval(ctxt);
10838}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010839
10840/**
10841 * xmlXPathEval:
10842 * @str: the XPath expression
10843 * @ctx: the XPath context
10844 *
10845 * Evaluate the XPath Location Path in the given context.
10846 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010847 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010848 * the caller has to free the object.
10849 */
10850xmlXPathObjectPtr
10851xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
10852 xmlXPathParserContextPtr ctxt;
10853 xmlXPathObjectPtr res, tmp, init = NULL;
10854 int stack = 0;
10855
10856 xmlXPathInit();
10857
10858 CHECK_CONTEXT(ctx)
10859
10860 ctxt = xmlXPathNewParserContext(str, ctx);
10861 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010862
10863 if (ctxt->value == NULL) {
10864 xmlGenericError(xmlGenericErrorContext,
10865 "xmlXPathEval: evaluation failed\n");
10866 res = NULL;
10867 } else if (*ctxt->cur != 0) {
10868 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10869 res = NULL;
10870 } else {
10871 res = valuePop(ctxt);
10872 }
10873
10874 do {
10875 tmp = valuePop(ctxt);
10876 if (tmp != NULL) {
10877 if (tmp != init)
10878 stack++;
10879 xmlXPathFreeObject(tmp);
10880 }
10881 } while (tmp != NULL);
10882 if ((stack != 0) && (res != NULL)) {
10883 xmlGenericError(xmlGenericErrorContext,
10884 "xmlXPathEval: %d object left on the stack\n",
10885 stack);
10886 }
10887 if (ctxt->error != XPATH_EXPRESSION_OK) {
10888 xmlXPathFreeObject(res);
10889 res = NULL;
10890 }
10891
Owen Taylor3473f882001-02-23 17:55:21 +000010892 xmlXPathFreeParserContext(ctxt);
10893 return(res);
10894}
10895
10896/**
10897 * xmlXPathEvalExpression:
10898 * @str: the XPath expression
10899 * @ctxt: the XPath context
10900 *
10901 * Evaluate the XPath expression in the given context.
10902 *
10903 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
10904 * the caller has to free the object.
10905 */
10906xmlXPathObjectPtr
10907xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
10908 xmlXPathParserContextPtr pctxt;
10909 xmlXPathObjectPtr res, tmp;
10910 int stack = 0;
10911
10912 xmlXPathInit();
10913
10914 CHECK_CONTEXT(ctxt)
10915
10916 pctxt = xmlXPathNewParserContext(str, ctxt);
10917 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010918
10919 if (*pctxt->cur != 0) {
10920 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10921 res = NULL;
10922 } else {
10923 res = valuePop(pctxt);
10924 }
10925 do {
10926 tmp = valuePop(pctxt);
10927 if (tmp != NULL) {
10928 xmlXPathFreeObject(tmp);
10929 stack++;
10930 }
10931 } while (tmp != NULL);
10932 if ((stack != 0) && (res != NULL)) {
10933 xmlGenericError(xmlGenericErrorContext,
10934 "xmlXPathEvalExpression: %d object left on the stack\n",
10935 stack);
10936 }
10937 xmlXPathFreeParserContext(pctxt);
10938 return(res);
10939}
10940
Daniel Veillard42766c02002-08-22 20:52:17 +000010941/************************************************************************
10942 * *
10943 * Extra functions not pertaining to the XPath spec *
10944 * *
10945 ************************************************************************/
10946/**
10947 * xmlXPathEscapeUriFunction:
10948 * @ctxt: the XPath Parser context
10949 * @nargs: the number of arguments
10950 *
10951 * Implement the escape-uri() XPath function
10952 * string escape-uri(string $str, bool $escape-reserved)
10953 *
10954 * This function applies the URI escaping rules defined in section 2 of [RFC
10955 * 2396] to the string supplied as $uri-part, which typically represents all
10956 * or part of a URI. The effect of the function is to replace any special
10957 * character in the string by an escape sequence of the form %xx%yy...,
10958 * where xxyy... is the hexadecimal representation of the octets used to
10959 * represent the character in UTF-8.
10960 *
10961 * The set of characters that are escaped depends on the setting of the
10962 * boolean argument $escape-reserved.
10963 *
10964 * If $escape-reserved is true, all characters are escaped other than lower
10965 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
10966 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
10967 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
10968 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
10969 * A-F).
10970 *
10971 * If $escape-reserved is false, the behavior differs in that characters
10972 * referred to in [RFC 2396] as reserved characters are not escaped. These
10973 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
10974 *
10975 * [RFC 2396] does not define whether escaped URIs should use lower case or
10976 * upper case for hexadecimal digits. To ensure that escaped URIs can be
10977 * compared using string comparison functions, this function must always use
10978 * the upper-case letters A-F.
10979 *
10980 * Generally, $escape-reserved should be set to true when escaping a string
10981 * that is to form a single part of a URI, and to false when escaping an
10982 * entire URI or URI reference.
10983 *
10984 * In the case of non-ascii characters, the string is encoded according to
10985 * utf-8 and then converted according to RFC 2396.
10986 *
10987 * Examples
10988 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
10989 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
10990 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
10991 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
10992 *
10993 */
Daniel Veillard118aed72002-09-24 14:13:13 +000010994static void
Daniel Veillard42766c02002-08-22 20:52:17 +000010995xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
10996 xmlXPathObjectPtr str;
10997 int escape_reserved;
10998 xmlBufferPtr target;
10999 xmlChar *cptr;
11000 xmlChar escape[4];
11001
11002 CHECK_ARITY(2);
11003
11004 escape_reserved = xmlXPathPopBoolean(ctxt);
11005
11006 CAST_TO_STRING;
11007 str = valuePop(ctxt);
11008
11009 target = xmlBufferCreate();
11010
11011 escape[0] = '%';
11012 escape[3] = 0;
11013
11014 if (target) {
11015 for (cptr = str->stringval; *cptr; cptr++) {
11016 if ((*cptr >= 'A' && *cptr <= 'Z') ||
11017 (*cptr >= 'a' && *cptr <= 'z') ||
11018 (*cptr >= '0' && *cptr <= '9') ||
11019 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
11020 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
11021 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
11022 (*cptr == '%' &&
11023 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
11024 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
11025 (cptr[1] >= '0' && cptr[1] <= '9')) &&
11026 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
11027 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
11028 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
11029 (!escape_reserved &&
11030 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
11031 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
11032 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
11033 *cptr == ','))) {
11034 xmlBufferAdd(target, cptr, 1);
11035 } else {
11036 if ((*cptr >> 4) < 10)
11037 escape[1] = '0' + (*cptr >> 4);
11038 else
11039 escape[1] = 'A' - 10 + (*cptr >> 4);
11040 if ((*cptr & 0xF) < 10)
11041 escape[2] = '0' + (*cptr & 0xF);
11042 else
11043 escape[2] = 'A' - 10 + (*cptr & 0xF);
11044
11045 xmlBufferAdd(target, &escape[0], 3);
11046 }
11047 }
11048 }
11049 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
11050 xmlBufferFree(target);
11051 xmlXPathFreeObject(str);
11052}
11053
Owen Taylor3473f882001-02-23 17:55:21 +000011054/**
11055 * xmlXPathRegisterAllFunctions:
11056 * @ctxt: the XPath context
11057 *
11058 * Registers all default XPath functions in this context
11059 */
11060void
11061xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
11062{
11063 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
11064 xmlXPathBooleanFunction);
11065 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
11066 xmlXPathCeilingFunction);
11067 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
11068 xmlXPathCountFunction);
11069 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
11070 xmlXPathConcatFunction);
11071 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
11072 xmlXPathContainsFunction);
11073 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
11074 xmlXPathIdFunction);
11075 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
11076 xmlXPathFalseFunction);
11077 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
11078 xmlXPathFloorFunction);
11079 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
11080 xmlXPathLastFunction);
11081 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
11082 xmlXPathLangFunction);
11083 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
11084 xmlXPathLocalNameFunction);
11085 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
11086 xmlXPathNotFunction);
11087 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
11088 xmlXPathNameFunction);
11089 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
11090 xmlXPathNamespaceURIFunction);
11091 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
11092 xmlXPathNormalizeFunction);
11093 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
11094 xmlXPathNumberFunction);
11095 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
11096 xmlXPathPositionFunction);
11097 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
11098 xmlXPathRoundFunction);
11099 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
11100 xmlXPathStringFunction);
11101 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
11102 xmlXPathStringLengthFunction);
11103 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
11104 xmlXPathStartsWithFunction);
11105 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
11106 xmlXPathSubstringFunction);
11107 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
11108 xmlXPathSubstringBeforeFunction);
11109 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
11110 xmlXPathSubstringAfterFunction);
11111 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
11112 xmlXPathSumFunction);
11113 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
11114 xmlXPathTrueFunction);
11115 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
11116 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000011117
11118 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
11119 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
11120 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000011121}
11122
11123#endif /* LIBXML_XPATH_ENABLED */