blob: 1dea4d0c763c5add976d5209506b2c6786186a1e [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * xpath.c: XML Path Language implementation
3 * XPath is a language for addressing parts of an XML document,
4 * designed to be used by both XSLT and XPointer
5 *
6 * Reference: W3C Recommendation 16 November 1999
7 * http://www.w3.org/TR/1999/REC-xpath-19991116
8 * Public reference:
9 * http://www.w3.org/TR/xpath
10 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011 * See Copyright for the status of this software
Owen Taylor3473f882001-02-23 17:55:21 +000012 *
Daniel Veillardc5d64342001-06-24 12:13:24 +000013 * Author: daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000014 *
Owen Taylor3473f882001-02-23 17:55:21 +000015 */
16
Daniel Veillard34ce8be2002-03-18 19:37:11 +000017#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000018#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000019#ifdef LIBXML_XPATH_ENABLED
20
Owen Taylor3473f882001-02-23 17:55:21 +000021#include <string.h>
22
23#ifdef HAVE_SYS_TYPES_H
24#include <sys/types.h>
25#endif
26#ifdef HAVE_MATH_H
27#include <math.h>
28#endif
29#ifdef HAVE_FLOAT_H
30#include <float.h>
31#endif
Owen Taylor3473f882001-02-23 17:55:21 +000032#ifdef HAVE_CTYPE_H
33#include <ctype.h>
34#endif
Daniel Veillard5792e162001-04-30 17:44:45 +000035#ifdef HAVE_SIGNAL_H
Daniel Veillardb45c43b2001-04-28 17:02:11 +000036#include <signal.h>
Daniel Veillardb45c43b2001-04-28 17:02:11 +000037#endif
Owen Taylor3473f882001-02-23 17:55:21 +000038
39#include <libxml/xmlmemory.h>
40#include <libxml/tree.h>
41#include <libxml/valid.h>
42#include <libxml/xpath.h>
43#include <libxml/xpathInternals.h>
44#include <libxml/parserInternals.h>
45#include <libxml/hash.h>
46#ifdef LIBXML_XPTR_ENABLED
47#include <libxml/xpointer.h>
48#endif
49#ifdef LIBXML_DEBUG_ENABLED
50#include <libxml/debugXML.h>
51#endif
52#include <libxml/xmlerror.h>
Daniel Veillard81463942001-10-16 12:34:39 +000053#include <libxml/threads.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000054#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000055
Daniel Veillard652d8a92003-02-04 19:28:49 +000056/*
57 * TODO: when compatibility allows remove all "fake node libxslt" strings
58 * the test should just be name[0] = ' '
59 */
Owen Taylor3473f882001-02-23 17:55:21 +000060/* #define DEBUG */
61/* #define DEBUG_STEP */
Daniel Veillardf06307e2001-07-03 10:35:50 +000062/* #define DEBUG_STEP_NTH */
Owen Taylor3473f882001-02-23 17:55:21 +000063/* #define DEBUG_EXPR */
Daniel Veillardf06307e2001-07-03 10:35:50 +000064/* #define DEBUG_EVAL_COUNTS */
Owen Taylor3473f882001-02-23 17:55:21 +000065
Daniel Veillard20ee8c02001-10-05 09:18:14 +000066static xmlNs xmlXPathXMLNamespaceStruct = {
67 NULL,
68 XML_NAMESPACE_DECL,
69 XML_XML_NAMESPACE,
Daniel Veillard118aed72002-09-24 14:13:13 +000070 BAD_CAST "xml",
71 NULL
Daniel Veillard20ee8c02001-10-05 09:18:14 +000072};
73static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
Daniel Veillardda423da2002-04-10 19:25:38 +000074#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +000075/*
76 * Optimizer is disabled only when threaded apps are detected while
77 * the library ain't compiled for thread safety.
78 */
79static int xmlXPathDisableOptimizer = 0;
80#endif
Daniel Veillard20ee8c02001-10-05 09:18:14 +000081
Daniel Veillard9e7160d2001-03-18 23:17:47 +000082/************************************************************************
83 * *
84 * Floating point stuff *
85 * *
86 ************************************************************************/
87
Daniel Veillardc0631a62001-09-20 13:56:06 +000088#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +000089#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +000090#endif
Daniel Veillardcda96922001-08-21 10:56:31 +000091#include "trionan.c"
92
Owen Taylor3473f882001-02-23 17:55:21 +000093/*
Owen Taylor3473f882001-02-23 17:55:21 +000094 * The lack of portability of this section of the libc is annoying !
95 */
96double xmlXPathNAN = 0;
97double xmlXPathPINF = 1;
98double xmlXPathNINF = -1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +000099double xmlXPathNZERO = 0;
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000100static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000101
Owen Taylor3473f882001-02-23 17:55:21 +0000102/**
103 * xmlXPathInit:
104 *
105 * Initialize the XPath environment
106 */
107void
108xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000109 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +0000110
Bjorn Reese45029602001-08-21 09:23:53 +0000111 xmlXPathPINF = trio_pinf();
112 xmlXPathNINF = trio_ninf();
113 xmlXPathNAN = trio_nan();
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000114 xmlXPathNZERO = trio_nzero();
Owen Taylor3473f882001-02-23 17:55:21 +0000115
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000116 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000117}
118
Daniel Veillardcda96922001-08-21 10:56:31 +0000119/**
120 * xmlXPathIsNaN:
121 * @val: a double value
122 *
123 * Provides a portable isnan() function to detect whether a double
124 * is a NotaNumber. Based on trio code
125 * http://sourceforge.net/projects/ctrio/
126 *
127 * Returns 1 if the value is a NaN, 0 otherwise
128 */
129int
130xmlXPathIsNaN(double val) {
131 return(trio_isnan(val));
132}
133
134/**
135 * xmlXPathIsInf:
136 * @val: a double value
137 *
138 * Provides a portable isinf() function to detect whether a double
139 * is a +Infinite or -Infinite. Based on trio code
140 * http://sourceforge.net/projects/ctrio/
141 *
142 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
143 */
144int
145xmlXPathIsInf(double val) {
146 return(trio_isinf(val));
147}
148
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000149/**
150 * xmlXPathGetSign:
151 * @val: a double value
152 *
153 * Provides a portable function to detect the sign of a double
154 * Modified from trio code
155 * http://sourceforge.net/projects/ctrio/
156 *
157 * Returns 1 if the value is Negative, 0 if positive
158 */
Daniel Veillard21458c82002-03-27 16:12:22 +0000159static int
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000160xmlXPathGetSign(double val) {
Daniel Veillard21458c82002-03-27 16:12:22 +0000161 return(trio_signbit(val));
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000162}
163
164
Owen Taylor3473f882001-02-23 17:55:21 +0000165/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000166 * *
167 * Parser Types *
168 * *
169 ************************************************************************/
170
171/*
172 * Types are private:
173 */
174
175typedef enum {
176 XPATH_OP_END=0,
177 XPATH_OP_AND,
178 XPATH_OP_OR,
179 XPATH_OP_EQUAL,
180 XPATH_OP_CMP,
181 XPATH_OP_PLUS,
182 XPATH_OP_MULT,
183 XPATH_OP_UNION,
184 XPATH_OP_ROOT,
185 XPATH_OP_NODE,
186 XPATH_OP_RESET,
187 XPATH_OP_COLLECT,
188 XPATH_OP_VALUE,
189 XPATH_OP_VARIABLE,
190 XPATH_OP_FUNCTION,
191 XPATH_OP_ARG,
192 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000193 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000194 XPATH_OP_SORT
195#ifdef LIBXML_XPTR_ENABLED
196 ,XPATH_OP_RANGETO
197#endif
198} xmlXPathOp;
199
200typedef enum {
201 AXIS_ANCESTOR = 1,
202 AXIS_ANCESTOR_OR_SELF,
203 AXIS_ATTRIBUTE,
204 AXIS_CHILD,
205 AXIS_DESCENDANT,
206 AXIS_DESCENDANT_OR_SELF,
207 AXIS_FOLLOWING,
208 AXIS_FOLLOWING_SIBLING,
209 AXIS_NAMESPACE,
210 AXIS_PARENT,
211 AXIS_PRECEDING,
212 AXIS_PRECEDING_SIBLING,
213 AXIS_SELF
214} xmlXPathAxisVal;
215
216typedef enum {
217 NODE_TEST_NONE = 0,
218 NODE_TEST_TYPE = 1,
219 NODE_TEST_PI = 2,
220 NODE_TEST_ALL = 3,
221 NODE_TEST_NS = 4,
222 NODE_TEST_NAME = 5
223} xmlXPathTestVal;
224
225typedef enum {
226 NODE_TYPE_NODE = 0,
227 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
228 NODE_TYPE_TEXT = XML_TEXT_NODE,
229 NODE_TYPE_PI = XML_PI_NODE
230} xmlXPathTypeVal;
231
232
233typedef struct _xmlXPathStepOp xmlXPathStepOp;
234typedef xmlXPathStepOp *xmlXPathStepOpPtr;
235struct _xmlXPathStepOp {
236 xmlXPathOp op;
237 int ch1;
238 int ch2;
239 int value;
240 int value2;
241 int value3;
242 void *value4;
243 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000244 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000245 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000246};
247
248struct _xmlXPathCompExpr {
249 int nbStep;
250 int maxStep;
251 xmlXPathStepOp *steps; /* ops for computation */
252 int last;
Daniel Veillard118aed72002-09-24 14:13:13 +0000253 xmlChar *expr;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000254#ifdef DEBUG_EVAL_COUNTS
255 int nb;
256 xmlChar *string;
257#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000258};
259
260/************************************************************************
261 * *
262 * Parser Type functions *
263 * *
264 ************************************************************************/
265
266/**
267 * xmlXPathNewCompExpr:
268 *
269 * Create a new Xpath component
270 *
271 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
272 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000273static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000274xmlXPathNewCompExpr(void) {
275 xmlXPathCompExprPtr cur;
276
277 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
278 if (cur == NULL) {
279 xmlGenericError(xmlGenericErrorContext,
280 "xmlXPathNewCompExpr : malloc failed\n");
281 return(NULL);
282 }
283 memset(cur, 0, sizeof(xmlXPathCompExpr));
284 cur->maxStep = 10;
285 cur->nbStep = 0;
286 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
287 sizeof(xmlXPathStepOp));
288 if (cur->steps == NULL) {
289 xmlGenericError(xmlGenericErrorContext,
290 "xmlXPathNewCompExpr : malloc failed\n");
291 xmlFree(cur);
292 return(NULL);
293 }
294 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
295 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000296#ifdef DEBUG_EVAL_COUNTS
297 cur->nb = 0;
298#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000299 return(cur);
300}
301
302/**
303 * xmlXPathFreeCompExpr:
304 * @comp: an XPATH comp
305 *
306 * Free up the memory allocated by @comp
307 */
308void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000309xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
310{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000311 xmlXPathStepOpPtr op;
312 int i;
313
314 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000315 return;
316 for (i = 0; i < comp->nbStep; i++) {
317 op = &comp->steps[i];
318 if (op->value4 != NULL) {
319 if (op->op == XPATH_OP_VALUE)
320 xmlXPathFreeObject(op->value4);
321 else
322 xmlFree(op->value4);
323 }
324 if (op->value5 != NULL)
325 xmlFree(op->value5);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000326 }
327 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000328 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000329 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000330#ifdef DEBUG_EVAL_COUNTS
331 if (comp->string != NULL) {
332 xmlFree(comp->string);
333 }
334#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000335 if (comp->expr != NULL) {
336 xmlFree(comp->expr);
337 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000338
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000339 xmlFree(comp);
340}
341
342/**
343 * xmlXPathCompExprAdd:
344 * @comp: the compiled expression
345 * @ch1: first child index
346 * @ch2: second child index
347 * @op: an op
348 * @value: the first int value
349 * @value2: the second int value
350 * @value3: the third int value
351 * @value4: the first string value
352 * @value5: the second string value
353 *
354 * Add an step to an XPath Compiled Expression
355 *
356 * Returns -1 in case of failure, the index otherwise
357 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000358static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000359xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
360 xmlXPathOp op, int value,
361 int value2, int value3, void *value4, void *value5) {
362 if (comp->nbStep >= comp->maxStep) {
363 xmlXPathStepOp *real;
364
365 comp->maxStep *= 2;
366 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
367 comp->maxStep * sizeof(xmlXPathStepOp));
368 if (real == NULL) {
369 comp->maxStep /= 2;
370 xmlGenericError(xmlGenericErrorContext,
371 "xmlXPathCompExprAdd : realloc failed\n");
372 return(-1);
373 }
374 comp->steps = real;
375 }
376 comp->last = comp->nbStep;
377 comp->steps[comp->nbStep].ch1 = ch1;
378 comp->steps[comp->nbStep].ch2 = ch2;
379 comp->steps[comp->nbStep].op = op;
380 comp->steps[comp->nbStep].value = value;
381 comp->steps[comp->nbStep].value2 = value2;
382 comp->steps[comp->nbStep].value3 = value3;
383 comp->steps[comp->nbStep].value4 = value4;
384 comp->steps[comp->nbStep].value5 = value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000385 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000386 return(comp->nbStep++);
387}
388
Daniel Veillardf06307e2001-07-03 10:35:50 +0000389/**
390 * xmlXPathCompSwap:
391 * @comp: the compiled expression
392 * @op: operation index
393 *
394 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000395 */
396static void
397xmlXPathCompSwap(xmlXPathStepOpPtr op) {
398 int tmp;
399
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000400#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000401 /*
402 * Since this manipulates possibly shared variables, this is
403 * disable if one detects that the library is used in a multithreaded
404 * application
405 */
406 if (xmlXPathDisableOptimizer)
407 return;
408#endif
409
Daniel Veillardf06307e2001-07-03 10:35:50 +0000410 tmp = op->ch1;
411 op->ch1 = op->ch2;
412 op->ch2 = tmp;
413}
414
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000415#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
416 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
417 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000418#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
419 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
420 (op), (val), (val2), (val3), (val4), (val5))
421
422#define PUSH_LEAVE_EXPR(op, val, val2) \
423xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
424
425#define PUSH_UNARY_EXPR(op, ch, val, val2) \
426xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
427
428#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
429xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), (val), (val2), 0 ,NULL ,NULL)
430
431/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000432 * *
433 * Debugging related functions *
434 * *
435 ************************************************************************/
436
437#define TODO \
438 xmlGenericError(xmlGenericErrorContext, \
439 "Unimplemented block at %s:%d\n", \
440 __FILE__, __LINE__);
441
442#define STRANGE \
443 xmlGenericError(xmlGenericErrorContext, \
444 "Internal error at %s:%d\n", \
445 __FILE__, __LINE__);
446
447#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000448static void
449xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000450 int i;
451 char shift[100];
452
453 for (i = 0;((i < depth) && (i < 25));i++)
454 shift[2 * i] = shift[2 * i + 1] = ' ';
455 shift[2 * i] = shift[2 * i + 1] = 0;
456 if (cur == NULL) {
457 fprintf(output, shift);
458 fprintf(output, "Node is NULL !\n");
459 return;
460
461 }
462
463 if ((cur->type == XML_DOCUMENT_NODE) ||
464 (cur->type == XML_HTML_DOCUMENT_NODE)) {
465 fprintf(output, shift);
466 fprintf(output, " /\n");
467 } else if (cur->type == XML_ATTRIBUTE_NODE)
468 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
469 else
470 xmlDebugDumpOneNode(output, cur, depth);
471}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000472static void
473xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000474 xmlNodePtr tmp;
475 int i;
476 char shift[100];
477
478 for (i = 0;((i < depth) && (i < 25));i++)
479 shift[2 * i] = shift[2 * i + 1] = ' ';
480 shift[2 * i] = shift[2 * i + 1] = 0;
481 if (cur == NULL) {
482 fprintf(output, shift);
483 fprintf(output, "Node is NULL !\n");
484 return;
485
486 }
487
488 while (cur != NULL) {
489 tmp = cur;
490 cur = cur->next;
491 xmlDebugDumpOneNode(output, tmp, depth);
492 }
493}
Owen Taylor3473f882001-02-23 17:55:21 +0000494
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000495static void
496xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000497 int i;
498 char shift[100];
499
500 for (i = 0;((i < depth) && (i < 25));i++)
501 shift[2 * i] = shift[2 * i + 1] = ' ';
502 shift[2 * i] = shift[2 * i + 1] = 0;
503
504 if (cur == NULL) {
505 fprintf(output, shift);
506 fprintf(output, "NodeSet is NULL !\n");
507 return;
508
509 }
510
Daniel Veillard911f49a2001-04-07 15:39:35 +0000511 if (cur != NULL) {
512 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
513 for (i = 0;i < cur->nodeNr;i++) {
514 fprintf(output, shift);
515 fprintf(output, "%d", i + 1);
516 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
517 }
Owen Taylor3473f882001-02-23 17:55:21 +0000518 }
519}
520
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000521static void
522xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000523 int i;
524 char shift[100];
525
526 for (i = 0;((i < depth) && (i < 25));i++)
527 shift[2 * i] = shift[2 * i + 1] = ' ';
528 shift[2 * i] = shift[2 * i + 1] = 0;
529
530 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
531 fprintf(output, shift);
532 fprintf(output, "Value Tree is NULL !\n");
533 return;
534
535 }
536
537 fprintf(output, shift);
538 fprintf(output, "%d", i + 1);
539 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
540}
Owen Taylor3473f882001-02-23 17:55:21 +0000541#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000542static void
543xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000544 int i;
545 char shift[100];
546
547 for (i = 0;((i < depth) && (i < 25));i++)
548 shift[2 * i] = shift[2 * i + 1] = ' ';
549 shift[2 * i] = shift[2 * i + 1] = 0;
550
551 if (cur == NULL) {
552 fprintf(output, shift);
553 fprintf(output, "LocationSet is NULL !\n");
554 return;
555
556 }
557
558 for (i = 0;i < cur->locNr;i++) {
559 fprintf(output, shift);
560 fprintf(output, "%d : ", i + 1);
561 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
562 }
563}
Daniel Veillard017b1082001-06-21 11:20:21 +0000564#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000565
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000566/**
567 * xmlXPathDebugDumpObject:
568 * @output: the FILE * to dump the output
569 * @cur: the object to inspect
570 * @depth: indentation level
571 *
572 * Dump the content of the object for debugging purposes
573 */
574void
575xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000576 int i;
577 char shift[100];
578
579 for (i = 0;((i < depth) && (i < 25));i++)
580 shift[2 * i] = shift[2 * i + 1] = ' ';
581 shift[2 * i] = shift[2 * i + 1] = 0;
582
583 fprintf(output, shift);
584
585 if (cur == NULL) {
586 fprintf(output, "Object is empty (NULL)\n");
587 return;
588 }
589 switch(cur->type) {
590 case XPATH_UNDEFINED:
591 fprintf(output, "Object is uninitialized\n");
592 break;
593 case XPATH_NODESET:
594 fprintf(output, "Object is a Node Set :\n");
595 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
596 break;
597 case XPATH_XSLT_TREE:
598 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000599 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000600 break;
601 case XPATH_BOOLEAN:
602 fprintf(output, "Object is a Boolean : ");
603 if (cur->boolval) fprintf(output, "true\n");
604 else fprintf(output, "false\n");
605 break;
606 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +0000607 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000608 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000609 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000610 break;
611 case -1:
612 fprintf(output, "Object is a number : -Infinity\n");
613 break;
614 default:
Daniel Veillardcda96922001-08-21 10:56:31 +0000615 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000616 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +0000617 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
618 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000619 } else {
620 fprintf(output, "Object is a number : %0g\n", cur->floatval);
621 }
622 }
Owen Taylor3473f882001-02-23 17:55:21 +0000623 break;
624 case XPATH_STRING:
625 fprintf(output, "Object is a string : ");
626 xmlDebugDumpString(output, cur->stringval);
627 fprintf(output, "\n");
628 break;
629 case XPATH_POINT:
630 fprintf(output, "Object is a point : index %d in node", cur->index);
631 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
632 fprintf(output, "\n");
633 break;
634 case XPATH_RANGE:
635 if ((cur->user2 == NULL) ||
636 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
637 fprintf(output, "Object is a collapsed range :\n");
638 fprintf(output, shift);
639 if (cur->index >= 0)
640 fprintf(output, "index %d in ", cur->index);
641 fprintf(output, "node\n");
642 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
643 depth + 1);
644 } else {
645 fprintf(output, "Object is a range :\n");
646 fprintf(output, shift);
647 fprintf(output, "From ");
648 if (cur->index >= 0)
649 fprintf(output, "index %d in ", cur->index);
650 fprintf(output, "node\n");
651 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
652 depth + 1);
653 fprintf(output, shift);
654 fprintf(output, "To ");
655 if (cur->index2 >= 0)
656 fprintf(output, "index %d in ", cur->index2);
657 fprintf(output, "node\n");
658 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
659 depth + 1);
660 fprintf(output, "\n");
661 }
662 break;
663 case XPATH_LOCATIONSET:
664#if defined(LIBXML_XPTR_ENABLED)
665 fprintf(output, "Object is a Location Set:\n");
666 xmlXPathDebugDumpLocationSet(output,
667 (xmlLocationSetPtr) cur->user, depth);
668#endif
669 break;
670 case XPATH_USERS:
671 fprintf(output, "Object is user defined\n");
672 break;
673 }
674}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000675
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000676static void
677xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000678 xmlXPathStepOpPtr op, int depth) {
679 int i;
680 char shift[100];
681
682 for (i = 0;((i < depth) && (i < 25));i++)
683 shift[2 * i] = shift[2 * i + 1] = ' ';
684 shift[2 * i] = shift[2 * i + 1] = 0;
685
686 fprintf(output, shift);
687 if (op == NULL) {
688 fprintf(output, "Step is NULL\n");
689 return;
690 }
691 switch (op->op) {
692 case XPATH_OP_END:
693 fprintf(output, "END"); break;
694 case XPATH_OP_AND:
695 fprintf(output, "AND"); break;
696 case XPATH_OP_OR:
697 fprintf(output, "OR"); break;
698 case XPATH_OP_EQUAL:
699 if (op->value)
700 fprintf(output, "EQUAL =");
701 else
702 fprintf(output, "EQUAL !=");
703 break;
704 case XPATH_OP_CMP:
705 if (op->value)
706 fprintf(output, "CMP <");
707 else
708 fprintf(output, "CMP >");
709 if (!op->value2)
710 fprintf(output, "=");
711 break;
712 case XPATH_OP_PLUS:
713 if (op->value == 0)
714 fprintf(output, "PLUS -");
715 else if (op->value == 1)
716 fprintf(output, "PLUS +");
717 else if (op->value == 2)
718 fprintf(output, "PLUS unary -");
719 else if (op->value == 3)
720 fprintf(output, "PLUS unary - -");
721 break;
722 case XPATH_OP_MULT:
723 if (op->value == 0)
724 fprintf(output, "MULT *");
725 else if (op->value == 1)
726 fprintf(output, "MULT div");
727 else
728 fprintf(output, "MULT mod");
729 break;
730 case XPATH_OP_UNION:
731 fprintf(output, "UNION"); break;
732 case XPATH_OP_ROOT:
733 fprintf(output, "ROOT"); break;
734 case XPATH_OP_NODE:
735 fprintf(output, "NODE"); break;
736 case XPATH_OP_RESET:
737 fprintf(output, "RESET"); break;
738 case XPATH_OP_SORT:
739 fprintf(output, "SORT"); break;
740 case XPATH_OP_COLLECT: {
741 xmlXPathAxisVal axis = op->value;
742 xmlXPathTestVal test = op->value2;
743 xmlXPathTypeVal type = op->value3;
744 const xmlChar *prefix = op->value4;
745 const xmlChar *name = op->value5;
746
747 fprintf(output, "COLLECT ");
748 switch (axis) {
749 case AXIS_ANCESTOR:
750 fprintf(output, " 'ancestors' "); break;
751 case AXIS_ANCESTOR_OR_SELF:
752 fprintf(output, " 'ancestors-or-self' "); break;
753 case AXIS_ATTRIBUTE:
754 fprintf(output, " 'attributes' "); break;
755 case AXIS_CHILD:
756 fprintf(output, " 'child' "); break;
757 case AXIS_DESCENDANT:
758 fprintf(output, " 'descendant' "); break;
759 case AXIS_DESCENDANT_OR_SELF:
760 fprintf(output, " 'descendant-or-self' "); break;
761 case AXIS_FOLLOWING:
762 fprintf(output, " 'following' "); break;
763 case AXIS_FOLLOWING_SIBLING:
764 fprintf(output, " 'following-siblings' "); break;
765 case AXIS_NAMESPACE:
766 fprintf(output, " 'namespace' "); break;
767 case AXIS_PARENT:
768 fprintf(output, " 'parent' "); break;
769 case AXIS_PRECEDING:
770 fprintf(output, " 'preceding' "); break;
771 case AXIS_PRECEDING_SIBLING:
772 fprintf(output, " 'preceding-sibling' "); break;
773 case AXIS_SELF:
774 fprintf(output, " 'self' "); break;
775 }
776 switch (test) {
777 case NODE_TEST_NONE:
778 fprintf(output, "'none' "); break;
779 case NODE_TEST_TYPE:
780 fprintf(output, "'type' "); break;
781 case NODE_TEST_PI:
782 fprintf(output, "'PI' "); break;
783 case NODE_TEST_ALL:
784 fprintf(output, "'all' "); break;
785 case NODE_TEST_NS:
786 fprintf(output, "'namespace' "); break;
787 case NODE_TEST_NAME:
788 fprintf(output, "'name' "); break;
789 }
790 switch (type) {
791 case NODE_TYPE_NODE:
792 fprintf(output, "'node' "); break;
793 case NODE_TYPE_COMMENT:
794 fprintf(output, "'comment' "); break;
795 case NODE_TYPE_TEXT:
796 fprintf(output, "'text' "); break;
797 case NODE_TYPE_PI:
798 fprintf(output, "'PI' "); break;
799 }
800 if (prefix != NULL)
801 fprintf(output, "%s:", prefix);
802 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +0000803 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000804 break;
805
806 }
807 case XPATH_OP_VALUE: {
808 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
809
810 fprintf(output, "ELEM ");
811 xmlXPathDebugDumpObject(output, object, 0);
812 goto finish;
813 }
814 case XPATH_OP_VARIABLE: {
815 const xmlChar *prefix = op->value5;
816 const xmlChar *name = op->value4;
817
818 if (prefix != NULL)
819 fprintf(output, "VARIABLE %s:%s", prefix, name);
820 else
821 fprintf(output, "VARIABLE %s", name);
822 break;
823 }
824 case XPATH_OP_FUNCTION: {
825 int nbargs = op->value;
826 const xmlChar *prefix = op->value5;
827 const xmlChar *name = op->value4;
828
829 if (prefix != NULL)
830 fprintf(output, "FUNCTION %s:%s(%d args)",
831 prefix, name, nbargs);
832 else
833 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
834 break;
835 }
836 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
837 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000838 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +0000839#ifdef LIBXML_XPTR_ENABLED
840 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
841#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000842 default:
843 fprintf(output, "UNKNOWN %d\n", op->op); return;
844 }
845 fprintf(output, "\n");
846finish:
847 if (op->ch1 >= 0)
848 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
849 if (op->ch2 >= 0)
850 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
851}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000852
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000853/**
854 * xmlXPathDebugDumpCompExpr:
855 * @output: the FILE * for the output
856 * @comp: the precompiled XPath expression
857 * @depth: the indentation level.
858 *
859 * Dumps the tree of the compiled XPath expression.
860 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000861void
862xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
863 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000864 int i;
865 char shift[100];
866
867 for (i = 0;((i < depth) && (i < 25));i++)
868 shift[2 * i] = shift[2 * i + 1] = ' ';
869 shift[2 * i] = shift[2 * i + 1] = 0;
870
871 fprintf(output, shift);
872
873 if (comp == NULL) {
874 fprintf(output, "Compiled Expression is NULL\n");
875 return;
876 }
877 fprintf(output, "Compiled Expression : %d elements\n",
878 comp->nbStep);
879 i = comp->last;
880 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
881}
Daniel Veillard017b1082001-06-21 11:20:21 +0000882#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000883
884/************************************************************************
885 * *
886 * Parser stacks related functions and macros *
887 * *
888 ************************************************************************/
889
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000890/**
891 * valuePop:
892 * @ctxt: an XPath evaluation context
893 *
894 * Pops the top XPath object from the value stack
895 *
896 * Returns the XPath object just removed
897 */
Daniel Veillard1c732d22002-11-30 11:22:59 +0000898extern xmlXPathObjectPtr
899valuePop(xmlXPathParserContextPtr ctxt)
900{
901 xmlXPathObjectPtr ret;
902
903 if (ctxt->valueNr <= 0)
904 return (0);
905 ctxt->valueNr--;
906 if (ctxt->valueNr > 0)
907 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
908 else
909 ctxt->value = NULL;
910 ret = ctxt->valueTab[ctxt->valueNr];
911 ctxt->valueTab[ctxt->valueNr] = 0;
912 return (ret);
913}
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000914/**
915 * valuePush:
916 * @ctxt: an XPath evaluation context
917 * @value: the XPath object
918 *
919 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000920 *
921 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000922 */
Daniel Veillard1c732d22002-11-30 11:22:59 +0000923extern int
924valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
925{
926 if (ctxt->valueNr >= ctxt->valueMax) {
927 ctxt->valueMax *= 2;
928 ctxt->valueTab =
929 (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
930 ctxt->valueMax *
931 sizeof(ctxt->valueTab[0]));
932 if (ctxt->valueTab == NULL) {
933 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
934 return (0);
935 }
936 }
937 ctxt->valueTab[ctxt->valueNr] = value;
938 ctxt->value = value;
939 return (ctxt->valueNr++);
940}
Owen Taylor3473f882001-02-23 17:55:21 +0000941
Thomas Broyerf06a3d82001-07-16 04:52:57 +0000942/**
943 * xmlXPathPopBoolean:
944 * @ctxt: an XPath parser context
945 *
946 * Pops a boolean from the stack, handling conversion if needed.
947 * Check error with #xmlXPathCheckError.
948 *
949 * Returns the boolean
950 */
951int
952xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
953 xmlXPathObjectPtr obj;
954 int ret;
955
956 obj = valuePop(ctxt);
957 if (obj == NULL) {
958 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
959 return(0);
960 }
961 ret = xmlXPathCastToBoolean(obj);
962 xmlXPathFreeObject(obj);
963 return(ret);
964}
965
966/**
967 * xmlXPathPopNumber:
968 * @ctxt: an XPath parser context
969 *
970 * Pops a number from the stack, handling conversion if needed.
971 * Check error with #xmlXPathCheckError.
972 *
973 * Returns the number
974 */
975double
976xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
977 xmlXPathObjectPtr obj;
978 double ret;
979
980 obj = valuePop(ctxt);
981 if (obj == NULL) {
982 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
983 return(0);
984 }
985 ret = xmlXPathCastToNumber(obj);
986 xmlXPathFreeObject(obj);
987 return(ret);
988}
989
990/**
991 * xmlXPathPopString:
992 * @ctxt: an XPath parser context
993 *
994 * Pops a string from the stack, handling conversion if needed.
995 * Check error with #xmlXPathCheckError.
996 *
997 * Returns the string
998 */
999xmlChar *
1000xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
1001 xmlXPathObjectPtr obj;
1002 xmlChar * ret;
1003
1004 obj = valuePop(ctxt);
1005 if (obj == NULL) {
1006 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1007 return(NULL);
1008 }
1009 ret = xmlXPathCastToString(obj);
1010 /* TODO: needs refactoring somewhere else */
1011 if (obj->stringval == ret)
1012 obj->stringval = NULL;
1013 xmlXPathFreeObject(obj);
1014 return(ret);
1015}
1016
1017/**
1018 * xmlXPathPopNodeSet:
1019 * @ctxt: an XPath parser context
1020 *
1021 * Pops a node-set from the stack, handling conversion if needed.
1022 * Check error with #xmlXPathCheckError.
1023 *
1024 * Returns the node-set
1025 */
1026xmlNodeSetPtr
1027xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
1028 xmlXPathObjectPtr obj;
1029 xmlNodeSetPtr ret;
1030
1031 if (ctxt->value == NULL) {
1032 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1033 return(NULL);
1034 }
1035 if (!xmlXPathStackIsNodeSet(ctxt)) {
1036 xmlXPathSetTypeError(ctxt);
1037 return(NULL);
1038 }
1039 obj = valuePop(ctxt);
1040 ret = obj->nodesetval;
1041 xmlXPathFreeNodeSetList(obj);
1042 return(ret);
1043}
1044
1045/**
1046 * xmlXPathPopExternal:
1047 * @ctxt: an XPath parser context
1048 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001049 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001050 * Check error with #xmlXPathCheckError.
1051 *
1052 * Returns the object
1053 */
1054void *
1055xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1056 xmlXPathObjectPtr obj;
1057 void * ret;
1058
1059 if (ctxt->value == NULL) {
1060 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1061 return(NULL);
1062 }
1063 if (ctxt->value->type != XPATH_USERS) {
1064 xmlXPathSetTypeError(ctxt);
1065 return(NULL);
1066 }
1067 obj = valuePop(ctxt);
1068 ret = obj->user;
1069 xmlXPathFreeObject(obj);
1070 return(ret);
1071}
1072
Owen Taylor3473f882001-02-23 17:55:21 +00001073/*
1074 * Macros for accessing the content. Those should be used only by the parser,
1075 * and not exported.
1076 *
1077 * Dirty macros, i.e. one need to make assumption on the context to use them
1078 *
1079 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1080 * CUR returns the current xmlChar value, i.e. a 8 bit value
1081 * in ISO-Latin or UTF-8.
1082 * This should be used internally by the parser
1083 * only to compare to ASCII values otherwise it would break when
1084 * running with UTF-8 encoding.
1085 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1086 * to compare on ASCII based substring.
1087 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1088 * strings within the parser.
1089 * CURRENT Returns the current char value, with the full decoding of
1090 * UTF-8 if we are using this mode. It returns an int.
1091 * NEXT Skip to the next character, this does the proper decoding
1092 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1093 * It returns the pointer to the current xmlChar.
1094 */
1095
1096#define CUR (*ctxt->cur)
1097#define SKIP(val) ctxt->cur += (val)
1098#define NXT(val) ctxt->cur[(val)]
1099#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001100#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1101
1102#define COPY_BUF(l,b,i,v) \
1103 if (l == 1) b[i++] = (xmlChar) v; \
1104 else i += xmlCopyChar(l,&b[i],v)
1105
1106#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001107
1108#define SKIP_BLANKS \
1109 while (IS_BLANK(*(ctxt->cur))) NEXT
1110
1111#define CURRENT (*ctxt->cur)
1112#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1113
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001114
1115#ifndef DBL_DIG
1116#define DBL_DIG 16
1117#endif
1118#ifndef DBL_EPSILON
1119#define DBL_EPSILON 1E-9
1120#endif
1121
1122#define UPPER_DOUBLE 1E9
1123#define LOWER_DOUBLE 1E-5
1124
1125#define INTEGER_DIGITS DBL_DIG
1126#define FRACTION_DIGITS (DBL_DIG + 1)
1127#define EXPONENT_DIGITS (3 + 2)
1128
1129/**
1130 * xmlXPathFormatNumber:
1131 * @number: number to format
1132 * @buffer: output buffer
1133 * @buffersize: size of output buffer
1134 *
1135 * Convert the number into a string representation.
1136 */
1137static void
1138xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1139{
Daniel Veillardcda96922001-08-21 10:56:31 +00001140 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001141 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001142 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001143 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001144 break;
1145 case -1:
1146 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001147 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001148 break;
1149 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001150 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001151 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001152 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001153 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001154 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001155 } else if (number == ((int) number)) {
1156 char work[30];
1157 char *ptr, *cur;
1158 int res, value = (int) number;
1159
1160 ptr = &buffer[0];
1161 if (value < 0) {
1162 *ptr++ = '-';
1163 value = -value;
1164 }
1165 if (value == 0) {
1166 *ptr++ = '0';
1167 } else {
1168 cur = &work[0];
1169 while (value != 0) {
1170 res = value % 10;
1171 value = value / 10;
1172 *cur++ = '0' + res;
1173 }
1174 cur--;
1175 while ((cur >= &work[0]) && (ptr - buffer < buffersize)) {
1176 *ptr++ = *cur--;
1177 }
1178 }
1179 if (ptr - buffer < buffersize) {
1180 *ptr = 0;
1181 } else if (buffersize > 0) {
1182 ptr--;
1183 *ptr = 0;
1184 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001185 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001186 /* 3 is sign, decimal point, and terminating zero */
1187 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1188 int integer_place, fraction_place;
1189 char *ptr;
1190 char *after_fraction;
1191 double absolute_value;
1192 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001193
Bjorn Reese70a9da52001-04-21 16:57:29 +00001194 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001195
Bjorn Reese70a9da52001-04-21 16:57:29 +00001196 /*
1197 * First choose format - scientific or regular floating point.
1198 * In either case, result is in work, and after_fraction points
1199 * just past the fractional part.
1200 */
1201 if ( ((absolute_value > UPPER_DOUBLE) ||
1202 (absolute_value < LOWER_DOUBLE)) &&
1203 (absolute_value != 0.0) ) {
1204 /* Use scientific notation */
1205 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1206 fraction_place = DBL_DIG - 1;
1207 snprintf(work, sizeof(work),"%*.*e",
1208 integer_place, fraction_place, number);
1209 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001210 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001211 else {
1212 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001213 if (absolute_value > 0.0)
1214 integer_place = 1 + (int)log10(absolute_value);
1215 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001216 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001217 fraction_place = (integer_place > 0)
1218 ? DBL_DIG - integer_place
1219 : DBL_DIG;
1220 size = snprintf(work, sizeof(work), "%0.*f",
1221 fraction_place, number);
1222 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001223 }
1224
Bjorn Reese70a9da52001-04-21 16:57:29 +00001225 /* Remove fractional trailing zeroes */
1226 ptr = after_fraction;
1227 while (*(--ptr) == '0')
1228 ;
1229 if (*ptr != '.')
1230 ptr++;
1231 strcpy(ptr, after_fraction);
1232
1233 /* Finally copy result back to caller */
1234 size = strlen(work) + 1;
1235 if (size > buffersize) {
1236 work[buffersize - 1] = 0;
1237 size = buffersize;
1238 }
1239 memcpy(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001240 }
1241 break;
1242 }
1243}
1244
Owen Taylor3473f882001-02-23 17:55:21 +00001245/************************************************************************
1246 * *
1247 * Error handling routines *
1248 * *
1249 ************************************************************************/
1250
1251
Daniel Veillardb44025c2001-10-11 22:55:55 +00001252static const char *xmlXPathErrorMessages[] = {
Owen Taylor3473f882001-02-23 17:55:21 +00001253 "Ok",
1254 "Number encoding",
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001255 "Unfinished literal",
1256 "Start of literal",
Owen Taylor3473f882001-02-23 17:55:21 +00001257 "Expected $ for variable reference",
1258 "Undefined variable",
1259 "Invalid predicate",
1260 "Invalid expression",
1261 "Missing closing curly brace",
1262 "Unregistered function",
1263 "Invalid operand",
1264 "Invalid type",
1265 "Invalid number of arguments",
1266 "Invalid context size",
1267 "Invalid context position",
1268 "Memory allocation error",
1269 "Syntax error",
1270 "Resource error",
1271 "Sub resource error",
Daniel Veillard61d80a22001-04-27 17:13:01 +00001272 "Undefined namespace prefix",
1273 "Encoding error",
1274 "Char out of XML range"
Owen Taylor3473f882001-02-23 17:55:21 +00001275};
1276
1277/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001278 * xmlXPatherror:
Owen Taylor3473f882001-02-23 17:55:21 +00001279 * @ctxt: the XPath Parser context
1280 * @file: the file name
1281 * @line: the line number
1282 * @no: the error number
1283 *
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001284 * Formats an error message.
Owen Taylor3473f882001-02-23 17:55:21 +00001285 */
1286void
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00001287xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
1288 int line ATTRIBUTE_UNUSED, int no) {
Owen Taylor3473f882001-02-23 17:55:21 +00001289 int n;
1290 const xmlChar *cur;
1291 const xmlChar *base;
1292
Owen Taylor3473f882001-02-23 17:55:21 +00001293 cur = ctxt->cur;
1294 base = ctxt->base;
Daniel Veillard118aed72002-09-24 14:13:13 +00001295 if ((cur == NULL) || (base == NULL)) {
1296 if ((ctxt->comp != NULL) && (ctxt->comp->expr != NULL)) {
1297 xmlGenericError(xmlGenericErrorContext,
1298 "XPath error %s in %s\n", xmlXPathErrorMessages[no],
1299 ctxt->comp->expr);
1300 } else {
1301 xmlGenericError(xmlGenericErrorContext,
1302 "XPath error %s\n", xmlXPathErrorMessages[no]);
1303 }
1304
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001305 return;
Daniel Veillard118aed72002-09-24 14:13:13 +00001306 }
1307 xmlGenericError(xmlGenericErrorContext,
1308 "XPath error %s\n", xmlXPathErrorMessages[no]);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001309
Owen Taylor3473f882001-02-23 17:55:21 +00001310 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
1311 cur--;
1312 }
1313 n = 0;
1314 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
1315 cur--;
1316 if ((*cur == '\n') || (*cur == '\r')) cur++;
1317 base = cur;
1318 n = 0;
1319 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
1320 xmlGenericError(xmlGenericErrorContext, "%c", (unsigned char) *cur++);
1321 n++;
1322 }
1323 xmlGenericError(xmlGenericErrorContext, "\n");
1324 cur = ctxt->cur;
1325 while ((*cur == '\n') || (*cur == '\r'))
1326 cur--;
1327 n = 0;
1328 while ((cur != base) && (n++ < 80)) {
1329 xmlGenericError(xmlGenericErrorContext, " ");
1330 base++;
1331 }
1332 xmlGenericError(xmlGenericErrorContext,"^\n");
1333}
1334
1335
1336/************************************************************************
1337 * *
1338 * Routines to handle NodeSets *
1339 * *
1340 ************************************************************************/
1341
1342/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001343 * xmlXPathOrderDocElems:
1344 * @doc: an input document
1345 *
1346 * Call this routine to speed up XPath computation on static documents.
1347 * This stamps all the element nodes with the document order
1348 * Like for line information, the order is kept in the element->content
1349 * field, the value stored is actually - the node number (startting at -1)
1350 * to be able to differenciate from line numbers.
1351 *
1352 * Returns the number of element found in the document or -1 in case
1353 * of error.
1354 */
1355long
1356xmlXPathOrderDocElems(xmlDocPtr doc) {
1357 long count = 0;
1358 xmlNodePtr cur;
1359
1360 if (doc == NULL)
1361 return(-1);
1362 cur = doc->children;
1363 while (cur != NULL) {
1364 if (cur->type == XML_ELEMENT_NODE) {
1365 cur->content = (void *) (-(++count));
1366 if (cur->children != NULL) {
1367 cur = cur->children;
1368 continue;
1369 }
1370 }
1371 if (cur->next != NULL) {
1372 cur = cur->next;
1373 continue;
1374 }
1375 do {
1376 cur = cur->parent;
1377 if (cur == NULL)
1378 break;
1379 if (cur == (xmlNodePtr) doc) {
1380 cur = NULL;
1381 break;
1382 }
1383 if (cur->next != NULL) {
1384 cur = cur->next;
1385 break;
1386 }
1387 } while (cur != NULL);
1388 }
1389 return(count);
1390}
1391
1392/**
Owen Taylor3473f882001-02-23 17:55:21 +00001393 * xmlXPathCmpNodes:
1394 * @node1: the first node
1395 * @node2: the second node
1396 *
1397 * Compare two nodes w.r.t document order
1398 *
1399 * Returns -2 in case of error 1 if first point < second point, 0 if
1400 * that's the same node, -1 otherwise
1401 */
1402int
1403xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1404 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001405 int attr1 = 0, attr2 = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001406 xmlNodePtr cur, root;
1407
1408 if ((node1 == NULL) || (node2 == NULL))
1409 return(-2);
1410 /*
1411 * a couple of optimizations which will avoid computations in most cases
1412 */
Daniel Veillardedfd5882003-03-07 14:20:40 +00001413 if (node1->type == XML_ATTRIBUTE_NODE) {
1414 attr1 = 1;
1415 node1 = node1->parent;
1416 }
1417 if (node2->type == XML_ATTRIBUTE_NODE) {
1418 attr2 = 1;
1419 node2 = node2->parent;
1420 }
1421 if (node1 == node2) {
1422 if (attr1 == attr2)
1423 return(0);
1424 if (attr2 == 1)
1425 return(1);
1426 return(-1);
1427 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00001428 if ((node1->type == XML_NAMESPACE_DECL) ||
1429 (node2->type == XML_NAMESPACE_DECL))
1430 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001431 if (node1 == node2->prev)
1432 return(1);
1433 if (node1 == node2->next)
1434 return(-1);
1435
1436 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001437 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001438 */
1439 if ((node1->type == XML_ELEMENT_NODE) &&
1440 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001441 (0 > (long) node1->content) &&
1442 (0 > (long) node2->content) &&
1443 (node1->doc == node2->doc)) {
1444 long l1, l2;
1445
1446 l1 = -((long) node1->content);
1447 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001448 if (l1 < l2)
1449 return(1);
1450 if (l1 > l2)
1451 return(-1);
1452 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001453
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001454 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001455 * compute depth to root
1456 */
1457 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1458 if (cur == node1)
1459 return(1);
1460 depth2++;
1461 }
1462 root = cur;
1463 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1464 if (cur == node2)
1465 return(-1);
1466 depth1++;
1467 }
1468 /*
1469 * Distinct document (or distinct entities :-( ) case.
1470 */
1471 if (root != cur) {
1472 return(-2);
1473 }
1474 /*
1475 * get the nearest common ancestor.
1476 */
1477 while (depth1 > depth2) {
1478 depth1--;
1479 node1 = node1->parent;
1480 }
1481 while (depth2 > depth1) {
1482 depth2--;
1483 node2 = node2->parent;
1484 }
1485 while (node1->parent != node2->parent) {
1486 node1 = node1->parent;
1487 node2 = node2->parent;
1488 /* should not happen but just in case ... */
1489 if ((node1 == NULL) || (node2 == NULL))
1490 return(-2);
1491 }
1492 /*
1493 * Find who's first.
1494 */
1495 if (node1 == node2->next)
1496 return(-1);
1497 for (cur = node1->next;cur != NULL;cur = cur->next)
1498 if (cur == node2)
1499 return(1);
1500 return(-1); /* assume there is no sibling list corruption */
1501}
1502
1503/**
1504 * xmlXPathNodeSetSort:
1505 * @set: the node set
1506 *
1507 * Sort the node set in document order
1508 */
1509void
1510xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001511 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001512 xmlNodePtr tmp;
1513
1514 if (set == NULL)
1515 return;
1516
1517 /* Use Shell's sort to sort the node-set */
1518 len = set->nodeNr;
1519 for (incr = len / 2; incr > 0; incr /= 2) {
1520 for (i = incr; i < len; i++) {
1521 j = i - incr;
1522 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001523 if (xmlXPathCmpNodes(set->nodeTab[j],
1524 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001525 tmp = set->nodeTab[j];
1526 set->nodeTab[j] = set->nodeTab[j + incr];
1527 set->nodeTab[j + incr] = tmp;
1528 j -= incr;
1529 } else
1530 break;
1531 }
1532 }
1533 }
1534}
1535
1536#define XML_NODESET_DEFAULT 10
1537/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001538 * xmlXPathNodeSetDupNs:
1539 * @node: the parent node of the namespace XPath node
1540 * @ns: the libxml namespace declaration node.
1541 *
1542 * Namespace node in libxml don't match the XPath semantic. In a node set
1543 * the namespace nodes are duplicated and the next pointer is set to the
1544 * parent node in the XPath semantic.
1545 *
1546 * Returns the newly created object.
1547 */
1548static xmlNodePtr
1549xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
1550 xmlNsPtr cur;
1551
1552 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1553 return(NULL);
1554 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
1555 return((xmlNodePtr) ns);
1556
1557 /*
1558 * Allocate a new Namespace and fill the fields.
1559 */
1560 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1561 if (cur == NULL) {
1562 xmlGenericError(xmlGenericErrorContext,
1563 "xmlXPathNodeSetDupNs : malloc failed\n");
1564 return(NULL);
1565 }
1566 memset(cur, 0, sizeof(xmlNs));
1567 cur->type = XML_NAMESPACE_DECL;
1568 if (ns->href != NULL)
1569 cur->href = xmlStrdup(ns->href);
1570 if (ns->prefix != NULL)
1571 cur->prefix = xmlStrdup(ns->prefix);
1572 cur->next = (xmlNsPtr) node;
1573 return((xmlNodePtr) cur);
1574}
1575
1576/**
1577 * xmlXPathNodeSetFreeNs:
1578 * @ns: the XPath namespace node found in a nodeset.
1579 *
1580 * Namespace node in libxml don't match the XPath semantic. In a node set
1581 * the namespace nodes are duplicated and the next pointer is set to the
1582 * parent node in the XPath semantic. Check if such a node need to be freed
1583 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001584void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001585xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
1586 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1587 return;
1588
1589 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
1590 if (ns->href != NULL)
1591 xmlFree((xmlChar *)ns->href);
1592 if (ns->prefix != NULL)
1593 xmlFree((xmlChar *)ns->prefix);
1594 xmlFree(ns);
1595 }
1596}
1597
1598/**
Owen Taylor3473f882001-02-23 17:55:21 +00001599 * xmlXPathNodeSetCreate:
1600 * @val: an initial xmlNodePtr, or NULL
1601 *
1602 * Create a new xmlNodeSetPtr of type double and of value @val
1603 *
1604 * Returns the newly created object.
1605 */
1606xmlNodeSetPtr
1607xmlXPathNodeSetCreate(xmlNodePtr val) {
1608 xmlNodeSetPtr ret;
1609
1610 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1611 if (ret == NULL) {
1612 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001613 "xmlXPathNodeSetCreate: out of memory\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001614 return(NULL);
1615 }
1616 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1617 if (val != NULL) {
1618 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1619 sizeof(xmlNodePtr));
1620 if (ret->nodeTab == NULL) {
1621 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001622 "xmlXPathNodeSetCreate: out of memory\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001623 return(NULL);
1624 }
1625 memset(ret->nodeTab, 0 ,
1626 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1627 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001628 if (val->type == XML_NAMESPACE_DECL) {
1629 xmlNsPtr ns = (xmlNsPtr) val;
1630
1631 ret->nodeTab[ret->nodeNr++] =
1632 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1633 } else
1634 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001635 }
1636 return(ret);
1637}
1638
1639/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001640 * xmlXPathNodeSetContains:
1641 * @cur: the node-set
1642 * @val: the node
1643 *
1644 * checks whether @cur contains @val
1645 *
1646 * Returns true (1) if @cur contains @val, false (0) otherwise
1647 */
1648int
1649xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1650 int i;
1651
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001652 if (val->type == XML_NAMESPACE_DECL) {
1653 for (i = 0; i < cur->nodeNr; i++) {
1654 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1655 xmlNsPtr ns1, ns2;
1656
1657 ns1 = (xmlNsPtr) val;
1658 ns2 = (xmlNsPtr) cur->nodeTab[i];
1659 if (ns1 == ns2)
1660 return(1);
1661 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
1662 (xmlStrEqual(ns1->prefix, ns2->prefix)))
1663 return(1);
1664 }
1665 }
1666 } else {
1667 for (i = 0; i < cur->nodeNr; i++) {
1668 if (cur->nodeTab[i] == val)
1669 return(1);
1670 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001671 }
1672 return(0);
1673}
1674
1675/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001676 * xmlXPathNodeSetAddNs:
1677 * @cur: the initial node set
1678 * @node: the hosting node
1679 * @ns: a the namespace node
1680 *
1681 * add a new namespace node to an existing NodeSet
1682 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00001683void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001684xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
1685 int i;
1686
1687 if ((ns == NULL) || (node == NULL) || (ns->type != XML_NAMESPACE_DECL) ||
1688 (node->type != XML_ELEMENT_NODE))
1689 return;
1690
1691 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1692 /*
1693 * check against doublons
1694 */
1695 for (i = 0;i < cur->nodeNr;i++) {
1696 if ((cur->nodeTab[i] != NULL) &&
1697 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00001698 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001699 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
1700 return;
1701 }
1702
1703 /*
1704 * grow the nodeTab if needed
1705 */
1706 if (cur->nodeMax == 0) {
1707 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1708 sizeof(xmlNodePtr));
1709 if (cur->nodeTab == NULL) {
1710 xmlGenericError(xmlGenericErrorContext,
1711 "xmlXPathNodeSetAdd: out of memory\n");
1712 return;
1713 }
1714 memset(cur->nodeTab, 0 ,
1715 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1716 cur->nodeMax = XML_NODESET_DEFAULT;
1717 } else if (cur->nodeNr == cur->nodeMax) {
1718 xmlNodePtr *temp;
1719
1720 cur->nodeMax *= 2;
1721 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1722 sizeof(xmlNodePtr));
1723 if (temp == NULL) {
1724 xmlGenericError(xmlGenericErrorContext,
1725 "xmlXPathNodeSetAdd: out of memory\n");
1726 return;
1727 }
1728 cur->nodeTab = temp;
1729 }
1730 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
1731}
1732
1733/**
Owen Taylor3473f882001-02-23 17:55:21 +00001734 * xmlXPathNodeSetAdd:
1735 * @cur: the initial node set
1736 * @val: a new xmlNodePtr
1737 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001738 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00001739 */
1740void
1741xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1742 int i;
1743
1744 if (val == NULL) return;
1745
Daniel Veillardef0b4502003-03-24 13:57:34 +00001746#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001747 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1748 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001749#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001750
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001751 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001752 /*
1753 * check against doublons
1754 */
1755 for (i = 0;i < cur->nodeNr;i++)
1756 if (cur->nodeTab[i] == val) return;
1757
1758 /*
1759 * grow the nodeTab if needed
1760 */
1761 if (cur->nodeMax == 0) {
1762 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1763 sizeof(xmlNodePtr));
1764 if (cur->nodeTab == NULL) {
1765 xmlGenericError(xmlGenericErrorContext,
1766 "xmlXPathNodeSetAdd: out of memory\n");
1767 return;
1768 }
1769 memset(cur->nodeTab, 0 ,
1770 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1771 cur->nodeMax = XML_NODESET_DEFAULT;
1772 } else if (cur->nodeNr == cur->nodeMax) {
1773 xmlNodePtr *temp;
1774
1775 cur->nodeMax *= 2;
1776 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1777 sizeof(xmlNodePtr));
1778 if (temp == NULL) {
1779 xmlGenericError(xmlGenericErrorContext,
1780 "xmlXPathNodeSetAdd: out of memory\n");
1781 return;
1782 }
1783 cur->nodeTab = temp;
1784 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001785 if (val->type == XML_NAMESPACE_DECL) {
1786 xmlNsPtr ns = (xmlNsPtr) val;
1787
1788 cur->nodeTab[cur->nodeNr++] =
1789 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1790 } else
1791 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001792}
1793
1794/**
1795 * xmlXPathNodeSetAddUnique:
1796 * @cur: the initial node set
1797 * @val: a new xmlNodePtr
1798 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001799 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00001800 * when we are sure the node is not already in the set.
1801 */
1802void
1803xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1804 if (val == NULL) return;
1805
Daniel Veillardef0b4502003-03-24 13:57:34 +00001806#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001807 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1808 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001809#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001810
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001811 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001812 /*
1813 * grow the nodeTab if needed
1814 */
1815 if (cur->nodeMax == 0) {
1816 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1817 sizeof(xmlNodePtr));
1818 if (cur->nodeTab == NULL) {
1819 xmlGenericError(xmlGenericErrorContext,
1820 "xmlXPathNodeSetAddUnique: out of memory\n");
1821 return;
1822 }
1823 memset(cur->nodeTab, 0 ,
1824 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1825 cur->nodeMax = XML_NODESET_DEFAULT;
1826 } else if (cur->nodeNr == cur->nodeMax) {
1827 xmlNodePtr *temp;
1828
1829 cur->nodeMax *= 2;
1830 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1831 sizeof(xmlNodePtr));
1832 if (temp == NULL) {
1833 xmlGenericError(xmlGenericErrorContext,
1834 "xmlXPathNodeSetAddUnique: out of memory\n");
1835 return;
1836 }
1837 cur->nodeTab = temp;
1838 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001839 if (val->type == XML_NAMESPACE_DECL) {
1840 xmlNsPtr ns = (xmlNsPtr) val;
1841
1842 cur->nodeTab[cur->nodeNr++] =
1843 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1844 } else
1845 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001846}
1847
1848/**
1849 * xmlXPathNodeSetMerge:
1850 * @val1: the first NodeSet or NULL
1851 * @val2: the second NodeSet
1852 *
1853 * Merges two nodesets, all nodes from @val2 are added to @val1
1854 * if @val1 is NULL, a new set is created and copied from @val2
1855 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001856 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00001857 */
1858xmlNodeSetPtr
1859xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001860 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001861
1862 if (val2 == NULL) return(val1);
1863 if (val1 == NULL) {
1864 val1 = xmlXPathNodeSetCreate(NULL);
1865 }
1866
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001867 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001868 initNr = val1->nodeNr;
1869
1870 for (i = 0;i < val2->nodeNr;i++) {
1871 /*
1872 * check against doublons
1873 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001874 skip = 0;
1875 for (j = 0; j < initNr; j++) {
1876 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1877 skip = 1;
1878 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001879 } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) &&
1880 (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) {
1881 xmlNsPtr ns1, ns2;
1882 ns1 = (xmlNsPtr) val1->nodeTab[j];
1883 ns2 = (xmlNsPtr) val2->nodeTab[i];
1884 if ((ns1->next == ns2->next) &&
1885 (xmlStrEqual(ns1->prefix, ns2->prefix))) {
1886 skip = 1;
1887 break;
1888 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001889 }
1890 }
1891 if (skip)
1892 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00001893
1894 /*
1895 * grow the nodeTab if needed
1896 */
1897 if (val1->nodeMax == 0) {
1898 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1899 sizeof(xmlNodePtr));
1900 if (val1->nodeTab == NULL) {
1901 xmlGenericError(xmlGenericErrorContext,
1902 "xmlXPathNodeSetMerge: out of memory\n");
1903 return(NULL);
1904 }
1905 memset(val1->nodeTab, 0 ,
1906 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1907 val1->nodeMax = XML_NODESET_DEFAULT;
1908 } else if (val1->nodeNr == val1->nodeMax) {
1909 xmlNodePtr *temp;
1910
1911 val1->nodeMax *= 2;
1912 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1913 sizeof(xmlNodePtr));
1914 if (temp == NULL) {
1915 xmlGenericError(xmlGenericErrorContext,
1916 "xmlXPathNodeSetMerge: out of memory\n");
1917 return(NULL);
1918 }
1919 val1->nodeTab = temp;
1920 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001921 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1922 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1923
1924 val1->nodeTab[val1->nodeNr++] =
1925 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1926 } else
1927 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00001928 }
1929
1930 return(val1);
1931}
1932
1933/**
Daniel Veillard75be0132002-03-13 10:03:35 +00001934 * xmlXPathNodeSetMergeUnique:
1935 * @val1: the first NodeSet or NULL
1936 * @val2: the second NodeSet
1937 *
1938 * Merges two nodesets, all nodes from @val2 are added to @val1
1939 * if @val1 is NULL, a new set is created and copied from @val2
1940 *
1941 * Returns @val1 once extended or NULL in case of error.
1942 */
1943static xmlNodeSetPtr
1944xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
1945 int i, initNr;
1946
1947 if (val2 == NULL) return(val1);
1948 if (val1 == NULL) {
1949 val1 = xmlXPathNodeSetCreate(NULL);
1950 }
1951
1952 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1953 initNr = val1->nodeNr;
1954
1955 for (i = 0;i < val2->nodeNr;i++) {
1956 /*
1957 * grow the nodeTab if needed
1958 */
1959 if (val1->nodeMax == 0) {
1960 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1961 sizeof(xmlNodePtr));
1962 if (val1->nodeTab == NULL) {
1963 xmlGenericError(xmlGenericErrorContext,
1964 "xmlXPathNodeSetMerge: out of memory\n");
1965 return(NULL);
1966 }
1967 memset(val1->nodeTab, 0 ,
1968 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1969 val1->nodeMax = XML_NODESET_DEFAULT;
1970 } else if (val1->nodeNr == val1->nodeMax) {
1971 xmlNodePtr *temp;
1972
1973 val1->nodeMax *= 2;
1974 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1975 sizeof(xmlNodePtr));
1976 if (temp == NULL) {
1977 xmlGenericError(xmlGenericErrorContext,
1978 "xmlXPathNodeSetMerge: out of memory\n");
1979 return(NULL);
1980 }
1981 val1->nodeTab = temp;
1982 }
1983 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1984 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1985
1986 val1->nodeTab[val1->nodeNr++] =
1987 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1988 } else
1989 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
1990 }
1991
1992 return(val1);
1993}
1994
1995/**
Owen Taylor3473f882001-02-23 17:55:21 +00001996 * xmlXPathNodeSetDel:
1997 * @cur: the initial node set
1998 * @val: an xmlNodePtr
1999 *
2000 * Removes an xmlNodePtr from an existing NodeSet
2001 */
2002void
2003xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
2004 int i;
2005
2006 if (cur == NULL) return;
2007 if (val == NULL) return;
2008
2009 /*
2010 * check against doublons
2011 */
2012 for (i = 0;i < cur->nodeNr;i++)
2013 if (cur->nodeTab[i] == val) break;
2014
2015 if (i >= cur->nodeNr) {
2016#ifdef DEBUG
2017 xmlGenericError(xmlGenericErrorContext,
2018 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
2019 val->name);
2020#endif
2021 return;
2022 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002023 if ((cur->nodeTab[i] != NULL) &&
2024 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
2025 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002026 cur->nodeNr--;
2027 for (;i < cur->nodeNr;i++)
2028 cur->nodeTab[i] = cur->nodeTab[i + 1];
2029 cur->nodeTab[cur->nodeNr] = NULL;
2030}
2031
2032/**
2033 * xmlXPathNodeSetRemove:
2034 * @cur: the initial node set
2035 * @val: the index to remove
2036 *
2037 * Removes an entry from an existing NodeSet list.
2038 */
2039void
2040xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
2041 if (cur == NULL) return;
2042 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002043 if ((cur->nodeTab[val] != NULL) &&
2044 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
2045 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00002046 cur->nodeNr--;
2047 for (;val < cur->nodeNr;val++)
2048 cur->nodeTab[val] = cur->nodeTab[val + 1];
2049 cur->nodeTab[cur->nodeNr] = NULL;
2050}
2051
2052/**
2053 * xmlXPathFreeNodeSet:
2054 * @obj: the xmlNodeSetPtr to free
2055 *
2056 * Free the NodeSet compound (not the actual nodes !).
2057 */
2058void
2059xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
2060 if (obj == NULL) return;
2061 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002062 int i;
2063
2064 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
2065 for (i = 0;i < obj->nodeNr;i++)
2066 if ((obj->nodeTab[i] != NULL) &&
2067 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
2068 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002069 xmlFree(obj->nodeTab);
2070 }
Owen Taylor3473f882001-02-23 17:55:21 +00002071 xmlFree(obj);
2072}
2073
2074/**
2075 * xmlXPathFreeValueTree:
2076 * @obj: the xmlNodeSetPtr to free
2077 *
2078 * Free the NodeSet compound and the actual tree, this is different
2079 * from xmlXPathFreeNodeSet()
2080 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002081static void
Owen Taylor3473f882001-02-23 17:55:21 +00002082xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
2083 int i;
2084
2085 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002086
2087 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002088 for (i = 0;i < obj->nodeNr;i++) {
2089 if (obj->nodeTab[i] != NULL) {
2090 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2091 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
2092 } else {
2093 xmlFreeNodeList(obj->nodeTab[i]);
2094 }
2095 }
2096 }
Owen Taylor3473f882001-02-23 17:55:21 +00002097 xmlFree(obj->nodeTab);
2098 }
Owen Taylor3473f882001-02-23 17:55:21 +00002099 xmlFree(obj);
2100}
2101
2102#if defined(DEBUG) || defined(DEBUG_STEP)
2103/**
2104 * xmlGenericErrorContextNodeSet:
2105 * @output: a FILE * for the output
2106 * @obj: the xmlNodeSetPtr to free
2107 *
2108 * Quick display of a NodeSet
2109 */
2110void
2111xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
2112 int i;
2113
2114 if (output == NULL) output = xmlGenericErrorContext;
2115 if (obj == NULL) {
2116 fprintf(output, "NodeSet == NULL !\n");
2117 return;
2118 }
2119 if (obj->nodeNr == 0) {
2120 fprintf(output, "NodeSet is empty\n");
2121 return;
2122 }
2123 if (obj->nodeTab == NULL) {
2124 fprintf(output, " nodeTab == NULL !\n");
2125 return;
2126 }
2127 for (i = 0; i < obj->nodeNr; i++) {
2128 if (obj->nodeTab[i] == NULL) {
2129 fprintf(output, " NULL !\n");
2130 return;
2131 }
2132 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
2133 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
2134 fprintf(output, " /");
2135 else if (obj->nodeTab[i]->name == NULL)
2136 fprintf(output, " noname!");
2137 else fprintf(output, " %s", obj->nodeTab[i]->name);
2138 }
2139 fprintf(output, "\n");
2140}
2141#endif
2142
2143/**
2144 * xmlXPathNewNodeSet:
2145 * @val: the NodePtr value
2146 *
2147 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2148 * it with the single Node @val
2149 *
2150 * Returns the newly created object.
2151 */
2152xmlXPathObjectPtr
2153xmlXPathNewNodeSet(xmlNodePtr val) {
2154 xmlXPathObjectPtr ret;
2155
2156 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2157 if (ret == NULL) {
2158 xmlGenericError(xmlGenericErrorContext,
2159 "xmlXPathNewNodeSet: out of memory\n");
2160 return(NULL);
2161 }
2162 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2163 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00002164 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002165 ret->nodesetval = xmlXPathNodeSetCreate(val);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002166 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002167 return(ret);
2168}
2169
2170/**
2171 * xmlXPathNewValueTree:
2172 * @val: the NodePtr value
2173 *
2174 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
2175 * it with the tree root @val
2176 *
2177 * Returns the newly created object.
2178 */
2179xmlXPathObjectPtr
2180xmlXPathNewValueTree(xmlNodePtr val) {
2181 xmlXPathObjectPtr ret;
2182
2183 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2184 if (ret == NULL) {
2185 xmlGenericError(xmlGenericErrorContext,
2186 "xmlXPathNewNodeSet: out of memory\n");
2187 return(NULL);
2188 }
2189 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2190 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002191 ret->boolval = 1;
2192 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00002193 ret->nodesetval = xmlXPathNodeSetCreate(val);
2194 return(ret);
2195}
2196
2197/**
2198 * xmlXPathNewNodeSetList:
2199 * @val: an existing NodeSet
2200 *
2201 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2202 * it with the Nodeset @val
2203 *
2204 * Returns the newly created object.
2205 */
2206xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002207xmlXPathNewNodeSetList(xmlNodeSetPtr val)
2208{
Owen Taylor3473f882001-02-23 17:55:21 +00002209 xmlXPathObjectPtr ret;
2210 int i;
2211
2212 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002213 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002214 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002215 ret = xmlXPathNewNodeSet(NULL);
2216 else {
2217 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
2218 for (i = 1; i < val->nodeNr; ++i)
2219 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2220 }
Owen Taylor3473f882001-02-23 17:55:21 +00002221
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002222 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002223}
2224
2225/**
2226 * xmlXPathWrapNodeSet:
2227 * @val: the NodePtr value
2228 *
2229 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2230 *
2231 * Returns the newly created object.
2232 */
2233xmlXPathObjectPtr
2234xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2235 xmlXPathObjectPtr ret;
2236
2237 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2238 if (ret == NULL) {
2239 xmlGenericError(xmlGenericErrorContext,
2240 "xmlXPathWrapNodeSet: out of memory\n");
2241 return(NULL);
2242 }
2243 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2244 ret->type = XPATH_NODESET;
2245 ret->nodesetval = val;
2246 return(ret);
2247}
2248
2249/**
2250 * xmlXPathFreeNodeSetList:
2251 * @obj: an existing NodeSetList object
2252 *
2253 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2254 * the list contrary to xmlXPathFreeObject().
2255 */
2256void
2257xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2258 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002259 xmlFree(obj);
2260}
2261
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002262/**
2263 * xmlXPathDifference:
2264 * @nodes1: a node-set
2265 * @nodes2: a node-set
2266 *
2267 * Implements the EXSLT - Sets difference() function:
2268 * node-set set:difference (node-set, node-set)
2269 *
2270 * Returns the difference between the two node sets, or nodes1 if
2271 * nodes2 is empty
2272 */
2273xmlNodeSetPtr
2274xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2275 xmlNodeSetPtr ret;
2276 int i, l1;
2277 xmlNodePtr cur;
2278
2279 if (xmlXPathNodeSetIsEmpty(nodes2))
2280 return(nodes1);
2281
2282 ret = xmlXPathNodeSetCreate(NULL);
2283 if (xmlXPathNodeSetIsEmpty(nodes1))
2284 return(ret);
2285
2286 l1 = xmlXPathNodeSetGetLength(nodes1);
2287
2288 for (i = 0; i < l1; i++) {
2289 cur = xmlXPathNodeSetItem(nodes1, i);
2290 if (!xmlXPathNodeSetContains(nodes2, cur))
2291 xmlXPathNodeSetAddUnique(ret, cur);
2292 }
2293 return(ret);
2294}
2295
2296/**
2297 * xmlXPathIntersection:
2298 * @nodes1: a node-set
2299 * @nodes2: a node-set
2300 *
2301 * Implements the EXSLT - Sets intersection() function:
2302 * node-set set:intersection (node-set, node-set)
2303 *
2304 * Returns a node set comprising the nodes that are within both the
2305 * node sets passed as arguments
2306 */
2307xmlNodeSetPtr
2308xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2309 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2310 int i, l1;
2311 xmlNodePtr cur;
2312
2313 if (xmlXPathNodeSetIsEmpty(nodes1))
2314 return(ret);
2315 if (xmlXPathNodeSetIsEmpty(nodes2))
2316 return(ret);
2317
2318 l1 = xmlXPathNodeSetGetLength(nodes1);
2319
2320 for (i = 0; i < l1; i++) {
2321 cur = xmlXPathNodeSetItem(nodes1, i);
2322 if (xmlXPathNodeSetContains(nodes2, cur))
2323 xmlXPathNodeSetAddUnique(ret, cur);
2324 }
2325 return(ret);
2326}
2327
2328/**
2329 * xmlXPathDistinctSorted:
2330 * @nodes: a node-set, sorted by document order
2331 *
2332 * Implements the EXSLT - Sets distinct() function:
2333 * node-set set:distinct (node-set)
2334 *
2335 * Returns a subset of the nodes contained in @nodes, or @nodes if
2336 * it is empty
2337 */
2338xmlNodeSetPtr
2339xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2340 xmlNodeSetPtr ret;
2341 xmlHashTablePtr hash;
2342 int i, l;
2343 xmlChar * strval;
2344 xmlNodePtr cur;
2345
2346 if (xmlXPathNodeSetIsEmpty(nodes))
2347 return(nodes);
2348
2349 ret = xmlXPathNodeSetCreate(NULL);
2350 l = xmlXPathNodeSetGetLength(nodes);
2351 hash = xmlHashCreate (l);
2352 for (i = 0; i < l; i++) {
2353 cur = xmlXPathNodeSetItem(nodes, i);
2354 strval = xmlXPathCastNodeToString(cur);
2355 if (xmlHashLookup(hash, strval) == NULL) {
2356 xmlHashAddEntry(hash, strval, strval);
2357 xmlXPathNodeSetAddUnique(ret, cur);
2358 } else {
2359 xmlFree(strval);
2360 }
2361 }
2362 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2363 return(ret);
2364}
2365
2366/**
2367 * xmlXPathDistinct:
2368 * @nodes: a node-set
2369 *
2370 * Implements the EXSLT - Sets distinct() function:
2371 * node-set set:distinct (node-set)
2372 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2373 * is called with the sorted node-set
2374 *
2375 * Returns a subset of the nodes contained in @nodes, or @nodes if
2376 * it is empty
2377 */
2378xmlNodeSetPtr
2379xmlXPathDistinct (xmlNodeSetPtr nodes) {
2380 if (xmlXPathNodeSetIsEmpty(nodes))
2381 return(nodes);
2382
2383 xmlXPathNodeSetSort(nodes);
2384 return(xmlXPathDistinctSorted(nodes));
2385}
2386
2387/**
2388 * xmlXPathHasSameNodes:
2389 * @nodes1: a node-set
2390 * @nodes2: a node-set
2391 *
2392 * Implements the EXSLT - Sets has-same-nodes function:
2393 * boolean set:has-same-node(node-set, node-set)
2394 *
2395 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2396 * otherwise
2397 */
2398int
2399xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2400 int i, l;
2401 xmlNodePtr cur;
2402
2403 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2404 xmlXPathNodeSetIsEmpty(nodes2))
2405 return(0);
2406
2407 l = xmlXPathNodeSetGetLength(nodes1);
2408 for (i = 0; i < l; i++) {
2409 cur = xmlXPathNodeSetItem(nodes1, i);
2410 if (xmlXPathNodeSetContains(nodes2, cur))
2411 return(1);
2412 }
2413 return(0);
2414}
2415
2416/**
2417 * xmlXPathNodeLeadingSorted:
2418 * @nodes: a node-set, sorted by document order
2419 * @node: a node
2420 *
2421 * Implements the EXSLT - Sets leading() function:
2422 * node-set set:leading (node-set, node-set)
2423 *
2424 * Returns the nodes in @nodes that precede @node in document order,
2425 * @nodes if @node is NULL or an empty node-set if @nodes
2426 * doesn't contain @node
2427 */
2428xmlNodeSetPtr
2429xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2430 int i, l;
2431 xmlNodePtr cur;
2432 xmlNodeSetPtr ret;
2433
2434 if (node == NULL)
2435 return(nodes);
2436
2437 ret = xmlXPathNodeSetCreate(NULL);
2438 if (xmlXPathNodeSetIsEmpty(nodes) ||
2439 (!xmlXPathNodeSetContains(nodes, node)))
2440 return(ret);
2441
2442 l = xmlXPathNodeSetGetLength(nodes);
2443 for (i = 0; i < l; i++) {
2444 cur = xmlXPathNodeSetItem(nodes, i);
2445 if (cur == node)
2446 break;
2447 xmlXPathNodeSetAddUnique(ret, cur);
2448 }
2449 return(ret);
2450}
2451
2452/**
2453 * xmlXPathNodeLeading:
2454 * @nodes: a node-set
2455 * @node: a node
2456 *
2457 * Implements the EXSLT - Sets leading() function:
2458 * node-set set:leading (node-set, node-set)
2459 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2460 * is called.
2461 *
2462 * Returns the nodes in @nodes that precede @node in document order,
2463 * @nodes if @node is NULL or an empty node-set if @nodes
2464 * doesn't contain @node
2465 */
2466xmlNodeSetPtr
2467xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2468 xmlXPathNodeSetSort(nodes);
2469 return(xmlXPathNodeLeadingSorted(nodes, node));
2470}
2471
2472/**
2473 * xmlXPathLeadingSorted:
2474 * @nodes1: a node-set, sorted by document order
2475 * @nodes2: a node-set, sorted by document order
2476 *
2477 * Implements the EXSLT - Sets leading() function:
2478 * node-set set:leading (node-set, node-set)
2479 *
2480 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2481 * in document order, @nodes1 if @nodes2 is NULL or empty or
2482 * an empty node-set if @nodes1 doesn't contain @nodes2
2483 */
2484xmlNodeSetPtr
2485xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2486 if (xmlXPathNodeSetIsEmpty(nodes2))
2487 return(nodes1);
2488 return(xmlXPathNodeLeadingSorted(nodes1,
2489 xmlXPathNodeSetItem(nodes2, 1)));
2490}
2491
2492/**
2493 * xmlXPathLeading:
2494 * @nodes1: a node-set
2495 * @nodes2: a node-set
2496 *
2497 * Implements the EXSLT - Sets leading() function:
2498 * node-set set:leading (node-set, node-set)
2499 * @nodes1 and @nodes2 are sorted by document order, then
2500 * #exslSetsLeadingSorted is called.
2501 *
2502 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2503 * in document order, @nodes1 if @nodes2 is NULL or empty or
2504 * an empty node-set if @nodes1 doesn't contain @nodes2
2505 */
2506xmlNodeSetPtr
2507xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2508 if (xmlXPathNodeSetIsEmpty(nodes2))
2509 return(nodes1);
2510 if (xmlXPathNodeSetIsEmpty(nodes1))
2511 return(xmlXPathNodeSetCreate(NULL));
2512 xmlXPathNodeSetSort(nodes1);
2513 xmlXPathNodeSetSort(nodes2);
2514 return(xmlXPathNodeLeadingSorted(nodes1,
2515 xmlXPathNodeSetItem(nodes2, 1)));
2516}
2517
2518/**
2519 * xmlXPathNodeTrailingSorted:
2520 * @nodes: a node-set, sorted by document order
2521 * @node: a node
2522 *
2523 * Implements the EXSLT - Sets trailing() function:
2524 * node-set set:trailing (node-set, node-set)
2525 *
2526 * Returns the nodes in @nodes that follow @node in document order,
2527 * @nodes if @node is NULL or an empty node-set if @nodes
2528 * doesn't contain @node
2529 */
2530xmlNodeSetPtr
2531xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2532 int i, l;
2533 xmlNodePtr cur;
2534 xmlNodeSetPtr ret;
2535
2536 if (node == NULL)
2537 return(nodes);
2538
2539 ret = xmlXPathNodeSetCreate(NULL);
2540 if (xmlXPathNodeSetIsEmpty(nodes) ||
2541 (!xmlXPathNodeSetContains(nodes, node)))
2542 return(ret);
2543
2544 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002545 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002546 cur = xmlXPathNodeSetItem(nodes, i);
2547 if (cur == node)
2548 break;
2549 xmlXPathNodeSetAddUnique(ret, cur);
2550 }
2551 return(ret);
2552}
2553
2554/**
2555 * xmlXPathNodeTrailing:
2556 * @nodes: a node-set
2557 * @node: a node
2558 *
2559 * Implements the EXSLT - Sets trailing() function:
2560 * node-set set:trailing (node-set, node-set)
2561 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2562 * is called.
2563 *
2564 * Returns the nodes in @nodes that follow @node in document order,
2565 * @nodes if @node is NULL or an empty node-set if @nodes
2566 * doesn't contain @node
2567 */
2568xmlNodeSetPtr
2569xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2570 xmlXPathNodeSetSort(nodes);
2571 return(xmlXPathNodeTrailingSorted(nodes, node));
2572}
2573
2574/**
2575 * xmlXPathTrailingSorted:
2576 * @nodes1: a node-set, sorted by document order
2577 * @nodes2: a node-set, sorted by document order
2578 *
2579 * Implements the EXSLT - Sets trailing() function:
2580 * node-set set:trailing (node-set, node-set)
2581 *
2582 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2583 * in document order, @nodes1 if @nodes2 is NULL or empty or
2584 * an empty node-set if @nodes1 doesn't contain @nodes2
2585 */
2586xmlNodeSetPtr
2587xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2588 if (xmlXPathNodeSetIsEmpty(nodes2))
2589 return(nodes1);
2590 return(xmlXPathNodeTrailingSorted(nodes1,
2591 xmlXPathNodeSetItem(nodes2, 0)));
2592}
2593
2594/**
2595 * xmlXPathTrailing:
2596 * @nodes1: a node-set
2597 * @nodes2: a node-set
2598 *
2599 * Implements the EXSLT - Sets trailing() function:
2600 * node-set set:trailing (node-set, node-set)
2601 * @nodes1 and @nodes2 are sorted by document order, then
2602 * #xmlXPathTrailingSorted is called.
2603 *
2604 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2605 * in document order, @nodes1 if @nodes2 is NULL or empty or
2606 * an empty node-set if @nodes1 doesn't contain @nodes2
2607 */
2608xmlNodeSetPtr
2609xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2610 if (xmlXPathNodeSetIsEmpty(nodes2))
2611 return(nodes1);
2612 if (xmlXPathNodeSetIsEmpty(nodes1))
2613 return(xmlXPathNodeSetCreate(NULL));
2614 xmlXPathNodeSetSort(nodes1);
2615 xmlXPathNodeSetSort(nodes2);
2616 return(xmlXPathNodeTrailingSorted(nodes1,
2617 xmlXPathNodeSetItem(nodes2, 0)));
2618}
2619
Owen Taylor3473f882001-02-23 17:55:21 +00002620/************************************************************************
2621 * *
2622 * Routines to handle extra functions *
2623 * *
2624 ************************************************************************/
2625
2626/**
2627 * xmlXPathRegisterFunc:
2628 * @ctxt: the XPath context
2629 * @name: the function name
2630 * @f: the function implementation or NULL
2631 *
2632 * Register a new function. If @f is NULL it unregisters the function
2633 *
2634 * Returns 0 in case of success, -1 in case of error
2635 */
2636int
2637xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2638 xmlXPathFunction f) {
2639 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2640}
2641
2642/**
2643 * xmlXPathRegisterFuncNS:
2644 * @ctxt: the XPath context
2645 * @name: the function name
2646 * @ns_uri: the function namespace URI
2647 * @f: the function implementation or NULL
2648 *
2649 * Register a new function. If @f is NULL it unregisters the function
2650 *
2651 * Returns 0 in case of success, -1 in case of error
2652 */
2653int
2654xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2655 const xmlChar *ns_uri, xmlXPathFunction f) {
2656 if (ctxt == NULL)
2657 return(-1);
2658 if (name == NULL)
2659 return(-1);
2660
2661 if (ctxt->funcHash == NULL)
2662 ctxt->funcHash = xmlHashCreate(0);
2663 if (ctxt->funcHash == NULL)
2664 return(-1);
2665 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2666}
2667
2668/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002669 * xmlXPathRegisterFuncLookup:
2670 * @ctxt: the XPath context
2671 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002672 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00002673 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002674 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00002675 */
2676void
2677xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2678 xmlXPathFuncLookupFunc f,
2679 void *funcCtxt) {
2680 if (ctxt == NULL)
2681 return;
2682 ctxt->funcLookupFunc = (void *) f;
2683 ctxt->funcLookupData = funcCtxt;
2684}
2685
2686/**
Owen Taylor3473f882001-02-23 17:55:21 +00002687 * xmlXPathFunctionLookup:
2688 * @ctxt: the XPath context
2689 * @name: the function name
2690 *
2691 * Search in the Function array of the context for the given
2692 * function.
2693 *
2694 * Returns the xmlXPathFunction or NULL if not found
2695 */
2696xmlXPathFunction
2697xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002698 if (ctxt == NULL)
2699 return (NULL);
2700
2701 if (ctxt->funcLookupFunc != NULL) {
2702 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002703 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002704
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002705 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002706 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002707 if (ret != NULL)
2708 return(ret);
2709 }
Owen Taylor3473f882001-02-23 17:55:21 +00002710 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2711}
2712
2713/**
2714 * xmlXPathFunctionLookupNS:
2715 * @ctxt: the XPath context
2716 * @name: the function name
2717 * @ns_uri: the function namespace URI
2718 *
2719 * Search in the Function array of the context for the given
2720 * function.
2721 *
2722 * Returns the xmlXPathFunction or NULL if not found
2723 */
2724xmlXPathFunction
2725xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2726 const xmlChar *ns_uri) {
2727 if (ctxt == NULL)
2728 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002729 if (name == NULL)
2730 return(NULL);
2731
Thomas Broyerba4ad322001-07-26 16:55:21 +00002732 if (ctxt->funcLookupFunc != NULL) {
2733 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002734 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002735
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002736 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002737 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002738 if (ret != NULL)
2739 return(ret);
2740 }
2741
2742 if (ctxt->funcHash == NULL)
2743 return(NULL);
2744
Owen Taylor3473f882001-02-23 17:55:21 +00002745 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2746}
2747
2748/**
2749 * xmlXPathRegisteredFuncsCleanup:
2750 * @ctxt: the XPath context
2751 *
2752 * Cleanup the XPath context data associated to registered functions
2753 */
2754void
2755xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2756 if (ctxt == NULL)
2757 return;
2758
2759 xmlHashFree(ctxt->funcHash, NULL);
2760 ctxt->funcHash = NULL;
2761}
2762
2763/************************************************************************
2764 * *
2765 * Routines to handle Variable *
2766 * *
2767 ************************************************************************/
2768
2769/**
2770 * xmlXPathRegisterVariable:
2771 * @ctxt: the XPath context
2772 * @name: the variable name
2773 * @value: the variable value or NULL
2774 *
2775 * Register a new variable value. If @value is NULL it unregisters
2776 * the variable
2777 *
2778 * Returns 0 in case of success, -1 in case of error
2779 */
2780int
2781xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2782 xmlXPathObjectPtr value) {
2783 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2784}
2785
2786/**
2787 * xmlXPathRegisterVariableNS:
2788 * @ctxt: the XPath context
2789 * @name: the variable name
2790 * @ns_uri: the variable namespace URI
2791 * @value: the variable value or NULL
2792 *
2793 * Register a new variable value. If @value is NULL it unregisters
2794 * the variable
2795 *
2796 * Returns 0 in case of success, -1 in case of error
2797 */
2798int
2799xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2800 const xmlChar *ns_uri,
2801 xmlXPathObjectPtr value) {
2802 if (ctxt == NULL)
2803 return(-1);
2804 if (name == NULL)
2805 return(-1);
2806
2807 if (ctxt->varHash == NULL)
2808 ctxt->varHash = xmlHashCreate(0);
2809 if (ctxt->varHash == NULL)
2810 return(-1);
2811 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2812 (void *) value,
2813 (xmlHashDeallocator)xmlXPathFreeObject));
2814}
2815
2816/**
2817 * xmlXPathRegisterVariableLookup:
2818 * @ctxt: the XPath context
2819 * @f: the lookup function
2820 * @data: the lookup data
2821 *
2822 * register an external mechanism to do variable lookup
2823 */
2824void
2825xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2826 xmlXPathVariableLookupFunc f, void *data) {
2827 if (ctxt == NULL)
2828 return;
2829 ctxt->varLookupFunc = (void *) f;
2830 ctxt->varLookupData = data;
2831}
2832
2833/**
2834 * xmlXPathVariableLookup:
2835 * @ctxt: the XPath context
2836 * @name: the variable name
2837 *
2838 * Search in the Variable array of the context for the given
2839 * variable value.
2840 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002841 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002842 */
2843xmlXPathObjectPtr
2844xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2845 if (ctxt == NULL)
2846 return(NULL);
2847
2848 if (ctxt->varLookupFunc != NULL) {
2849 xmlXPathObjectPtr ret;
2850
2851 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2852 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00002853 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002854 }
2855 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
2856}
2857
2858/**
2859 * xmlXPathVariableLookupNS:
2860 * @ctxt: the XPath context
2861 * @name: the variable name
2862 * @ns_uri: the variable namespace URI
2863 *
2864 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00002865 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00002866 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002867 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002868 */
2869xmlXPathObjectPtr
2870xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2871 const xmlChar *ns_uri) {
2872 if (ctxt == NULL)
2873 return(NULL);
2874
2875 if (ctxt->varLookupFunc != NULL) {
2876 xmlXPathObjectPtr ret;
2877
2878 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2879 (ctxt->varLookupData, name, ns_uri);
2880 if (ret != NULL) return(ret);
2881 }
2882
2883 if (ctxt->varHash == NULL)
2884 return(NULL);
2885 if (name == NULL)
2886 return(NULL);
2887
Daniel Veillard8c357d52001-07-03 23:43:33 +00002888 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
2889 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00002890}
2891
2892/**
2893 * xmlXPathRegisteredVariablesCleanup:
2894 * @ctxt: the XPath context
2895 *
2896 * Cleanup the XPath context data associated to registered variables
2897 */
2898void
2899xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
2900 if (ctxt == NULL)
2901 return;
2902
Daniel Veillard76d66f42001-05-16 21:05:17 +00002903 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00002904 ctxt->varHash = NULL;
2905}
2906
2907/**
2908 * xmlXPathRegisterNs:
2909 * @ctxt: the XPath context
2910 * @prefix: the namespace prefix
2911 * @ns_uri: the namespace name
2912 *
2913 * Register a new namespace. If @ns_uri is NULL it unregisters
2914 * the namespace
2915 *
2916 * Returns 0 in case of success, -1 in case of error
2917 */
2918int
2919xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
2920 const xmlChar *ns_uri) {
2921 if (ctxt == NULL)
2922 return(-1);
2923 if (prefix == NULL)
2924 return(-1);
2925
2926 if (ctxt->nsHash == NULL)
2927 ctxt->nsHash = xmlHashCreate(10);
2928 if (ctxt->nsHash == NULL)
2929 return(-1);
Daniel Veillard42766c02002-08-22 20:52:17 +00002930 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00002931 (xmlHashDeallocator)xmlFree));
2932}
2933
2934/**
2935 * xmlXPathNsLookup:
2936 * @ctxt: the XPath context
2937 * @prefix: the namespace prefix value
2938 *
2939 * Search in the namespace declaration array of the context for the given
2940 * namespace name associated to the given prefix
2941 *
2942 * Returns the value or NULL if not found
2943 */
2944const xmlChar *
2945xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
2946 if (ctxt == NULL)
2947 return(NULL);
2948 if (prefix == NULL)
2949 return(NULL);
2950
2951#ifdef XML_XML_NAMESPACE
2952 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
2953 return(XML_XML_NAMESPACE);
2954#endif
2955
Daniel Veillardc8f620b2001-04-30 20:31:33 +00002956 if (ctxt->namespaces != NULL) {
2957 int i;
2958
2959 for (i = 0;i < ctxt->nsNr;i++) {
2960 if ((ctxt->namespaces[i] != NULL) &&
2961 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
2962 return(ctxt->namespaces[i]->href);
2963 }
2964 }
Owen Taylor3473f882001-02-23 17:55:21 +00002965
2966 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
2967}
2968
2969/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002970 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00002971 * @ctxt: the XPath context
2972 *
2973 * Cleanup the XPath context data associated to registered variables
2974 */
2975void
2976xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
2977 if (ctxt == NULL)
2978 return;
2979
Daniel Veillard42766c02002-08-22 20:52:17 +00002980 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00002981 ctxt->nsHash = NULL;
2982}
2983
2984/************************************************************************
2985 * *
2986 * Routines to handle Values *
2987 * *
2988 ************************************************************************/
2989
2990/* Allocations are terrible, one need to optimize all this !!! */
2991
2992/**
2993 * xmlXPathNewFloat:
2994 * @val: the double value
2995 *
2996 * Create a new xmlXPathObjectPtr of type double and of value @val
2997 *
2998 * Returns the newly created object.
2999 */
3000xmlXPathObjectPtr
3001xmlXPathNewFloat(double val) {
3002 xmlXPathObjectPtr ret;
3003
3004 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3005 if (ret == NULL) {
3006 xmlGenericError(xmlGenericErrorContext,
3007 "xmlXPathNewFloat: out of memory\n");
3008 return(NULL);
3009 }
3010 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3011 ret->type = XPATH_NUMBER;
3012 ret->floatval = val;
3013 return(ret);
3014}
3015
3016/**
3017 * xmlXPathNewBoolean:
3018 * @val: the boolean value
3019 *
3020 * Create a new xmlXPathObjectPtr of type boolean and of value @val
3021 *
3022 * Returns the newly created object.
3023 */
3024xmlXPathObjectPtr
3025xmlXPathNewBoolean(int val) {
3026 xmlXPathObjectPtr ret;
3027
3028 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3029 if (ret == NULL) {
3030 xmlGenericError(xmlGenericErrorContext,
3031 "xmlXPathNewBoolean: out of memory\n");
3032 return(NULL);
3033 }
3034 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3035 ret->type = XPATH_BOOLEAN;
3036 ret->boolval = (val != 0);
3037 return(ret);
3038}
3039
3040/**
3041 * xmlXPathNewString:
3042 * @val: the xmlChar * value
3043 *
3044 * Create a new xmlXPathObjectPtr of type string and of value @val
3045 *
3046 * Returns the newly created object.
3047 */
3048xmlXPathObjectPtr
3049xmlXPathNewString(const xmlChar *val) {
3050 xmlXPathObjectPtr ret;
3051
3052 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3053 if (ret == NULL) {
3054 xmlGenericError(xmlGenericErrorContext,
3055 "xmlXPathNewString: out of memory\n");
3056 return(NULL);
3057 }
3058 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3059 ret->type = XPATH_STRING;
3060 if (val != NULL)
3061 ret->stringval = xmlStrdup(val);
3062 else
3063 ret->stringval = xmlStrdup((const xmlChar *)"");
3064 return(ret);
3065}
3066
3067/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003068 * xmlXPathWrapString:
3069 * @val: the xmlChar * value
3070 *
3071 * Wraps the @val string into an XPath object.
3072 *
3073 * Returns the newly created object.
3074 */
3075xmlXPathObjectPtr
3076xmlXPathWrapString (xmlChar *val) {
3077 xmlXPathObjectPtr ret;
3078
3079 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3080 if (ret == NULL) {
3081 xmlGenericError(xmlGenericErrorContext,
3082 "xmlXPathWrapString: out of memory\n");
3083 return(NULL);
3084 }
3085 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3086 ret->type = XPATH_STRING;
3087 ret->stringval = val;
3088 return(ret);
3089}
3090
3091/**
Owen Taylor3473f882001-02-23 17:55:21 +00003092 * xmlXPathNewCString:
3093 * @val: the char * value
3094 *
3095 * Create a new xmlXPathObjectPtr of type string and of value @val
3096 *
3097 * Returns the newly created object.
3098 */
3099xmlXPathObjectPtr
3100xmlXPathNewCString(const char *val) {
3101 xmlXPathObjectPtr ret;
3102
3103 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3104 if (ret == NULL) {
3105 xmlGenericError(xmlGenericErrorContext,
3106 "xmlXPathNewCString: out of memory\n");
3107 return(NULL);
3108 }
3109 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3110 ret->type = XPATH_STRING;
3111 ret->stringval = xmlStrdup(BAD_CAST val);
3112 return(ret);
3113}
3114
3115/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003116 * xmlXPathWrapCString:
3117 * @val: the char * value
3118 *
3119 * Wraps a string into an XPath object.
3120 *
3121 * Returns the newly created object.
3122 */
3123xmlXPathObjectPtr
3124xmlXPathWrapCString (char * val) {
3125 return(xmlXPathWrapString((xmlChar *)(val)));
3126}
3127
3128/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003129 * xmlXPathWrapExternal:
3130 * @val: the user data
3131 *
3132 * Wraps the @val data into an XPath object.
3133 *
3134 * Returns the newly created object.
3135 */
3136xmlXPathObjectPtr
3137xmlXPathWrapExternal (void *val) {
3138 xmlXPathObjectPtr ret;
3139
3140 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3141 if (ret == NULL) {
3142 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003143 "xmlXPathWrapExternal: out of memory\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003144 return(NULL);
3145 }
3146 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3147 ret->type = XPATH_USERS;
3148 ret->user = val;
3149 return(ret);
3150}
3151
3152/**
Owen Taylor3473f882001-02-23 17:55:21 +00003153 * xmlXPathObjectCopy:
3154 * @val: the original object
3155 *
3156 * allocate a new copy of a given object
3157 *
3158 * Returns the newly created object.
3159 */
3160xmlXPathObjectPtr
3161xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3162 xmlXPathObjectPtr ret;
3163
3164 if (val == NULL)
3165 return(NULL);
3166
3167 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3168 if (ret == NULL) {
3169 xmlGenericError(xmlGenericErrorContext,
3170 "xmlXPathObjectCopy: out of memory\n");
3171 return(NULL);
3172 }
3173 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3174 switch (val->type) {
3175 case XPATH_BOOLEAN:
3176 case XPATH_NUMBER:
3177 case XPATH_POINT:
3178 case XPATH_RANGE:
3179 break;
3180 case XPATH_STRING:
3181 ret->stringval = xmlStrdup(val->stringval);
3182 break;
3183 case XPATH_XSLT_TREE:
3184 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003185 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003186 xmlNodePtr cur, tmp;
3187 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003188
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003189 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00003190 top = xmlNewDoc(NULL);
3191 top->name = (char *)
3192 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003193 ret->user = top;
3194 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003195 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003196 cur = val->nodesetval->nodeTab[0]->children;
3197 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003198 tmp = xmlDocCopyNode(cur, top, 1);
3199 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003200 cur = cur->next;
3201 }
3202 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003203 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003204 } else
Owen Taylor3473f882001-02-23 17:55:21 +00003205 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003206 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00003207 break;
3208 case XPATH_NODESET:
3209 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003210 /* Do not deallocate the copied tree value */
3211 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003212 break;
3213 case XPATH_LOCATIONSET:
3214#ifdef LIBXML_XPTR_ENABLED
3215 {
3216 xmlLocationSetPtr loc = val->user;
3217 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3218 break;
3219 }
3220#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00003221 case XPATH_USERS:
3222 ret->user = val->user;
3223 break;
3224 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00003225 xmlGenericError(xmlGenericErrorContext,
3226 "xmlXPathObjectCopy: unsupported type %d\n",
3227 val->type);
3228 break;
3229 }
3230 return(ret);
3231}
3232
3233/**
3234 * xmlXPathFreeObject:
3235 * @obj: the object to free
3236 *
3237 * Free up an xmlXPathObjectPtr object.
3238 */
3239void
3240xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3241 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003242 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00003243 if (obj->boolval) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003244 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003245 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00003246 xmlFreeNodeList((xmlNodePtr) obj->user);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003247 } else if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00003248 xmlXPathFreeValueTree(obj->nodesetval);
3249 } else {
3250 if (obj->nodesetval != NULL)
3251 xmlXPathFreeNodeSet(obj->nodesetval);
3252 }
Owen Taylor3473f882001-02-23 17:55:21 +00003253#ifdef LIBXML_XPTR_ENABLED
3254 } else if (obj->type == XPATH_LOCATIONSET) {
3255 if (obj->user != NULL)
3256 xmlXPtrFreeLocationSet(obj->user);
3257#endif
3258 } else if (obj->type == XPATH_STRING) {
3259 if (obj->stringval != NULL)
3260 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00003261 }
3262
Owen Taylor3473f882001-02-23 17:55:21 +00003263 xmlFree(obj);
3264}
3265
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003266
3267/************************************************************************
3268 * *
3269 * Type Casting Routines *
3270 * *
3271 ************************************************************************/
3272
3273/**
3274 * xmlXPathCastBooleanToString:
3275 * @val: a boolean
3276 *
3277 * Converts a boolean to its string value.
3278 *
3279 * Returns a newly allocated string.
3280 */
3281xmlChar *
3282xmlXPathCastBooleanToString (int val) {
3283 xmlChar *ret;
3284 if (val)
3285 ret = xmlStrdup((const xmlChar *) "true");
3286 else
3287 ret = xmlStrdup((const xmlChar *) "false");
3288 return(ret);
3289}
3290
3291/**
3292 * xmlXPathCastNumberToString:
3293 * @val: a number
3294 *
3295 * Converts a number to its string value.
3296 *
3297 * Returns a newly allocated string.
3298 */
3299xmlChar *
3300xmlXPathCastNumberToString (double val) {
3301 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00003302 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003303 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003304 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003305 break;
3306 case -1:
3307 ret = xmlStrdup((const xmlChar *) "-Infinity");
3308 break;
3309 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003310 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003311 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00003312 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
3313 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003314 } else {
3315 /* could be improved */
3316 char buf[100];
3317 xmlXPathFormatNumber(val, buf, 100);
3318 ret = xmlStrdup((const xmlChar *) buf);
3319 }
3320 }
3321 return(ret);
3322}
3323
3324/**
3325 * xmlXPathCastNodeToString:
3326 * @node: a node
3327 *
3328 * Converts a node to its string value.
3329 *
3330 * Returns a newly allocated string.
3331 */
3332xmlChar *
3333xmlXPathCastNodeToString (xmlNodePtr node) {
3334 return(xmlNodeGetContent(node));
3335}
3336
3337/**
3338 * xmlXPathCastNodeSetToString:
3339 * @ns: a node-set
3340 *
3341 * Converts a node-set to its string value.
3342 *
3343 * Returns a newly allocated string.
3344 */
3345xmlChar *
3346xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3347 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3348 return(xmlStrdup((const xmlChar *) ""));
3349
3350 xmlXPathNodeSetSort(ns);
3351 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3352}
3353
3354/**
3355 * xmlXPathCastToString:
3356 * @val: an XPath object
3357 *
3358 * Converts an existing object to its string() equivalent
3359 *
3360 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003361 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003362 * string object).
3363 */
3364xmlChar *
3365xmlXPathCastToString(xmlXPathObjectPtr val) {
3366 xmlChar *ret = NULL;
3367
3368 if (val == NULL)
3369 return(xmlStrdup((const xmlChar *) ""));
3370 switch (val->type) {
3371 case XPATH_UNDEFINED:
3372#ifdef DEBUG_EXPR
3373 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3374#endif
3375 ret = xmlStrdup((const xmlChar *) "");
3376 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003377 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003378 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003379 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3380 break;
3381 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00003382 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003383 case XPATH_BOOLEAN:
3384 ret = xmlXPathCastBooleanToString(val->boolval);
3385 break;
3386 case XPATH_NUMBER: {
3387 ret = xmlXPathCastNumberToString(val->floatval);
3388 break;
3389 }
3390 case XPATH_USERS:
3391 case XPATH_POINT:
3392 case XPATH_RANGE:
3393 case XPATH_LOCATIONSET:
3394 TODO
3395 ret = xmlStrdup((const xmlChar *) "");
3396 break;
3397 }
3398 return(ret);
3399}
3400
3401/**
3402 * xmlXPathConvertString:
3403 * @val: an XPath object
3404 *
3405 * Converts an existing object to its string() equivalent
3406 *
3407 * Returns the new object, the old one is freed (or the operation
3408 * is done directly on @val)
3409 */
3410xmlXPathObjectPtr
3411xmlXPathConvertString(xmlXPathObjectPtr val) {
3412 xmlChar *res = NULL;
3413
3414 if (val == NULL)
3415 return(xmlXPathNewCString(""));
3416
3417 switch (val->type) {
3418 case XPATH_UNDEFINED:
3419#ifdef DEBUG_EXPR
3420 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3421#endif
3422 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003423 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003424 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003425 res = xmlXPathCastNodeSetToString(val->nodesetval);
3426 break;
3427 case XPATH_STRING:
3428 return(val);
3429 case XPATH_BOOLEAN:
3430 res = xmlXPathCastBooleanToString(val->boolval);
3431 break;
3432 case XPATH_NUMBER:
3433 res = xmlXPathCastNumberToString(val->floatval);
3434 break;
3435 case XPATH_USERS:
3436 case XPATH_POINT:
3437 case XPATH_RANGE:
3438 case XPATH_LOCATIONSET:
3439 TODO;
3440 break;
3441 }
3442 xmlXPathFreeObject(val);
3443 if (res == NULL)
3444 return(xmlXPathNewCString(""));
3445 return(xmlXPathWrapString(res));
3446}
3447
3448/**
3449 * xmlXPathCastBooleanToNumber:
3450 * @val: a boolean
3451 *
3452 * Converts a boolean to its number value
3453 *
3454 * Returns the number value
3455 */
3456double
3457xmlXPathCastBooleanToNumber(int val) {
3458 if (val)
3459 return(1.0);
3460 return(0.0);
3461}
3462
3463/**
3464 * xmlXPathCastStringToNumber:
3465 * @val: a string
3466 *
3467 * Converts a string to its number value
3468 *
3469 * Returns the number value
3470 */
3471double
3472xmlXPathCastStringToNumber(const xmlChar * val) {
3473 return(xmlXPathStringEvalNumber(val));
3474}
3475
3476/**
3477 * xmlXPathCastNodeToNumber:
3478 * @node: a node
3479 *
3480 * Converts a node to its number value
3481 *
3482 * Returns the number value
3483 */
3484double
3485xmlXPathCastNodeToNumber (xmlNodePtr node) {
3486 xmlChar *strval;
3487 double ret;
3488
3489 if (node == NULL)
3490 return(xmlXPathNAN);
3491 strval = xmlXPathCastNodeToString(node);
3492 if (strval == NULL)
3493 return(xmlXPathNAN);
3494 ret = xmlXPathCastStringToNumber(strval);
3495 xmlFree(strval);
3496
3497 return(ret);
3498}
3499
3500/**
3501 * xmlXPathCastNodeSetToNumber:
3502 * @ns: a node-set
3503 *
3504 * Converts a node-set to its number value
3505 *
3506 * Returns the number value
3507 */
3508double
3509xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3510 xmlChar *str;
3511 double ret;
3512
3513 if (ns == NULL)
3514 return(xmlXPathNAN);
3515 str = xmlXPathCastNodeSetToString(ns);
3516 ret = xmlXPathCastStringToNumber(str);
3517 xmlFree(str);
3518 return(ret);
3519}
3520
3521/**
3522 * xmlXPathCastToNumber:
3523 * @val: an XPath object
3524 *
3525 * Converts an XPath object to its number value
3526 *
3527 * Returns the number value
3528 */
3529double
3530xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3531 double ret = 0.0;
3532
3533 if (val == NULL)
3534 return(xmlXPathNAN);
3535 switch (val->type) {
3536 case XPATH_UNDEFINED:
3537#ifdef DEGUB_EXPR
3538 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3539#endif
3540 ret = xmlXPathNAN;
3541 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003542 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003543 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003544 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3545 break;
3546 case XPATH_STRING:
3547 ret = xmlXPathCastStringToNumber(val->stringval);
3548 break;
3549 case XPATH_NUMBER:
3550 ret = val->floatval;
3551 break;
3552 case XPATH_BOOLEAN:
3553 ret = xmlXPathCastBooleanToNumber(val->boolval);
3554 break;
3555 case XPATH_USERS:
3556 case XPATH_POINT:
3557 case XPATH_RANGE:
3558 case XPATH_LOCATIONSET:
3559 TODO;
3560 ret = xmlXPathNAN;
3561 break;
3562 }
3563 return(ret);
3564}
3565
3566/**
3567 * xmlXPathConvertNumber:
3568 * @val: an XPath object
3569 *
3570 * Converts an existing object to its number() equivalent
3571 *
3572 * Returns the new object, the old one is freed (or the operation
3573 * is done directly on @val)
3574 */
3575xmlXPathObjectPtr
3576xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3577 xmlXPathObjectPtr ret;
3578
3579 if (val == NULL)
3580 return(xmlXPathNewFloat(0.0));
3581 if (val->type == XPATH_NUMBER)
3582 return(val);
3583 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3584 xmlXPathFreeObject(val);
3585 return(ret);
3586}
3587
3588/**
3589 * xmlXPathCastNumberToBoolean:
3590 * @val: a number
3591 *
3592 * Converts a number to its boolean value
3593 *
3594 * Returns the boolean value
3595 */
3596int
3597xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003598 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003599 return(0);
3600 return(1);
3601}
3602
3603/**
3604 * xmlXPathCastStringToBoolean:
3605 * @val: a string
3606 *
3607 * Converts a string to its boolean value
3608 *
3609 * Returns the boolean value
3610 */
3611int
3612xmlXPathCastStringToBoolean (const xmlChar *val) {
3613 if ((val == NULL) || (xmlStrlen(val) == 0))
3614 return(0);
3615 return(1);
3616}
3617
3618/**
3619 * xmlXPathCastNodeSetToBoolean:
3620 * @ns: a node-set
3621 *
3622 * Converts a node-set to its boolean value
3623 *
3624 * Returns the boolean value
3625 */
3626int
3627xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3628 if ((ns == NULL) || (ns->nodeNr == 0))
3629 return(0);
3630 return(1);
3631}
3632
3633/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003634 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003635 * @val: an XPath object
3636 *
3637 * Converts an XPath object to its boolean value
3638 *
3639 * Returns the boolean value
3640 */
3641int
3642xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3643 int ret = 0;
3644
3645 if (val == NULL)
3646 return(0);
3647 switch (val->type) {
3648 case XPATH_UNDEFINED:
3649#ifdef DEBUG_EXPR
3650 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3651#endif
3652 ret = 0;
3653 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003654 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003655 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003656 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3657 break;
3658 case XPATH_STRING:
3659 ret = xmlXPathCastStringToBoolean(val->stringval);
3660 break;
3661 case XPATH_NUMBER:
3662 ret = xmlXPathCastNumberToBoolean(val->floatval);
3663 break;
3664 case XPATH_BOOLEAN:
3665 ret = val->boolval;
3666 break;
3667 case XPATH_USERS:
3668 case XPATH_POINT:
3669 case XPATH_RANGE:
3670 case XPATH_LOCATIONSET:
3671 TODO;
3672 ret = 0;
3673 break;
3674 }
3675 return(ret);
3676}
3677
3678
3679/**
3680 * xmlXPathConvertBoolean:
3681 * @val: an XPath object
3682 *
3683 * Converts an existing object to its boolean() equivalent
3684 *
3685 * Returns the new object, the old one is freed (or the operation
3686 * is done directly on @val)
3687 */
3688xmlXPathObjectPtr
3689xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3690 xmlXPathObjectPtr ret;
3691
3692 if (val == NULL)
3693 return(xmlXPathNewBoolean(0));
3694 if (val->type == XPATH_BOOLEAN)
3695 return(val);
3696 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3697 xmlXPathFreeObject(val);
3698 return(ret);
3699}
3700
Owen Taylor3473f882001-02-23 17:55:21 +00003701/************************************************************************
3702 * *
3703 * Routines to handle XPath contexts *
3704 * *
3705 ************************************************************************/
3706
3707/**
3708 * xmlXPathNewContext:
3709 * @doc: the XML document
3710 *
3711 * Create a new xmlXPathContext
3712 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00003713 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00003714 */
3715xmlXPathContextPtr
3716xmlXPathNewContext(xmlDocPtr doc) {
3717 xmlXPathContextPtr ret;
3718
3719 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3720 if (ret == NULL) {
3721 xmlGenericError(xmlGenericErrorContext,
3722 "xmlXPathNewContext: out of memory\n");
3723 return(NULL);
3724 }
3725 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3726 ret->doc = doc;
3727 ret->node = NULL;
3728
3729 ret->varHash = NULL;
3730
3731 ret->nb_types = 0;
3732 ret->max_types = 0;
3733 ret->types = NULL;
3734
3735 ret->funcHash = xmlHashCreate(0);
3736
3737 ret->nb_axis = 0;
3738 ret->max_axis = 0;
3739 ret->axis = NULL;
3740
3741 ret->nsHash = NULL;
3742 ret->user = NULL;
3743
3744 ret->contextSize = -1;
3745 ret->proximityPosition = -1;
3746
3747 xmlXPathRegisterAllFunctions(ret);
3748
3749 return(ret);
3750}
3751
3752/**
3753 * xmlXPathFreeContext:
3754 * @ctxt: the context to free
3755 *
3756 * Free up an xmlXPathContext
3757 */
3758void
3759xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3760 xmlXPathRegisteredNsCleanup(ctxt);
3761 xmlXPathRegisteredFuncsCleanup(ctxt);
3762 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003763 xmlFree(ctxt);
3764}
3765
3766/************************************************************************
3767 * *
3768 * Routines to handle XPath parser contexts *
3769 * *
3770 ************************************************************************/
3771
3772#define CHECK_CTXT(ctxt) \
3773 if (ctxt == NULL) { \
3774 xmlGenericError(xmlGenericErrorContext, \
3775 "%s:%d Internal error: ctxt == NULL\n", \
3776 __FILE__, __LINE__); \
3777 } \
3778
3779
3780#define CHECK_CONTEXT(ctxt) \
3781 if (ctxt == NULL) { \
3782 xmlGenericError(xmlGenericErrorContext, \
3783 "%s:%d Internal error: no context\n", \
3784 __FILE__, __LINE__); \
3785 } \
3786 else if (ctxt->doc == NULL) { \
3787 xmlGenericError(xmlGenericErrorContext, \
3788 "%s:%d Internal error: no document\n", \
3789 __FILE__, __LINE__); \
3790 } \
3791 else if (ctxt->doc->children == NULL) { \
3792 xmlGenericError(xmlGenericErrorContext, \
3793 "%s:%d Internal error: document without root\n", \
3794 __FILE__, __LINE__); \
3795 } \
3796
3797
3798/**
3799 * xmlXPathNewParserContext:
3800 * @str: the XPath expression
3801 * @ctxt: the XPath context
3802 *
3803 * Create a new xmlXPathParserContext
3804 *
3805 * Returns the xmlXPathParserContext just allocated.
3806 */
3807xmlXPathParserContextPtr
3808xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3809 xmlXPathParserContextPtr ret;
3810
3811 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3812 if (ret == NULL) {
3813 xmlGenericError(xmlGenericErrorContext,
3814 "xmlXPathNewParserContext: out of memory\n");
3815 return(NULL);
3816 }
3817 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3818 ret->cur = ret->base = str;
3819 ret->context = ctxt;
3820
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003821 ret->comp = xmlXPathNewCompExpr();
3822 if (ret->comp == NULL) {
3823 xmlFree(ret->valueTab);
3824 xmlFree(ret);
3825 return(NULL);
3826 }
3827
3828 return(ret);
3829}
3830
3831/**
3832 * xmlXPathCompParserContext:
3833 * @comp: the XPath compiled expression
3834 * @ctxt: the XPath context
3835 *
3836 * Create a new xmlXPathParserContext when processing a compiled expression
3837 *
3838 * Returns the xmlXPathParserContext just allocated.
3839 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003840static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003841xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3842 xmlXPathParserContextPtr ret;
3843
3844 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3845 if (ret == NULL) {
3846 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003847 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003848 return(NULL);
3849 }
3850 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3851
Owen Taylor3473f882001-02-23 17:55:21 +00003852 /* Allocate the value stack */
3853 ret->valueTab = (xmlXPathObjectPtr *)
3854 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003855 if (ret->valueTab == NULL) {
3856 xmlFree(ret);
3857 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003858 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003859 return(NULL);
3860 }
Owen Taylor3473f882001-02-23 17:55:21 +00003861 ret->valueNr = 0;
3862 ret->valueMax = 10;
3863 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003864
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00003865 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003866 ret->comp = comp;
3867
Owen Taylor3473f882001-02-23 17:55:21 +00003868 return(ret);
3869}
3870
3871/**
3872 * xmlXPathFreeParserContext:
3873 * @ctxt: the context to free
3874 *
3875 * Free up an xmlXPathParserContext
3876 */
3877void
3878xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
3879 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003880 xmlFree(ctxt->valueTab);
3881 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003882 if (ctxt->comp)
3883 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00003884 xmlFree(ctxt);
3885}
3886
3887/************************************************************************
3888 * *
3889 * The implicit core function library *
3890 * *
3891 ************************************************************************/
3892
Owen Taylor3473f882001-02-23 17:55:21 +00003893/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00003894 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00003895 * @node: a node pointer
3896 *
3897 * Function computing the beginning of the string value of the node,
3898 * used to speed up comparisons
3899 *
3900 * Returns an int usable as a hash
3901 */
3902static unsigned int
3903xmlXPathNodeValHash(xmlNodePtr node) {
3904 int len = 2;
3905 const xmlChar * string = NULL;
3906 xmlNodePtr tmp = NULL;
3907 unsigned int ret = 0;
3908
3909 if (node == NULL)
3910 return(0);
3911
Daniel Veillard9adc0462003-03-24 18:39:54 +00003912 if (node->type == XML_DOCUMENT_NODE) {
3913 tmp = xmlDocGetRootElement((xmlDocPtr) node);
3914 if (tmp == NULL)
3915 node = node->children;
3916 else
3917 node = tmp;
3918
3919 if (node == NULL)
3920 return(0);
3921 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003922
3923 switch (node->type) {
3924 case XML_COMMENT_NODE:
3925 case XML_PI_NODE:
3926 case XML_CDATA_SECTION_NODE:
3927 case XML_TEXT_NODE:
3928 string = node->content;
3929 if (string == NULL)
3930 return(0);
3931 if (string[0] == 0)
3932 return(0);
3933 return(((unsigned int) string[0]) +
3934 (((unsigned int) string[1]) << 8));
3935 case XML_NAMESPACE_DECL:
3936 string = ((xmlNsPtr)node)->href;
3937 if (string == NULL)
3938 return(0);
3939 if (string[0] == 0)
3940 return(0);
3941 return(((unsigned int) string[0]) +
3942 (((unsigned int) string[1]) << 8));
3943 case XML_ATTRIBUTE_NODE:
3944 tmp = ((xmlAttrPtr) node)->children;
3945 break;
3946 case XML_ELEMENT_NODE:
3947 tmp = node->children;
3948 break;
3949 default:
3950 return(0);
3951 }
3952 while (tmp != NULL) {
3953 switch (tmp->type) {
3954 case XML_COMMENT_NODE:
3955 case XML_PI_NODE:
3956 case XML_CDATA_SECTION_NODE:
3957 case XML_TEXT_NODE:
3958 string = tmp->content;
3959 break;
3960 case XML_NAMESPACE_DECL:
3961 string = ((xmlNsPtr)tmp)->href;
3962 break;
3963 default:
3964 break;
3965 }
3966 if ((string != NULL) && (string[0] != 0)) {
3967 if (string[0] == 0)
3968 return(0);
3969 if (len == 1) {
3970 return(ret + (((unsigned int) string[0]) << 8));
3971 }
3972 if (string[1] == 0) {
3973 len = 1;
3974 ret = (unsigned int) string[0];
3975 } else {
3976 return(((unsigned int) string[0]) +
3977 (((unsigned int) string[1]) << 8));
3978 }
3979 }
3980 /*
3981 * Skip to next node
3982 */
3983 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
3984 if (tmp->children->type != XML_ENTITY_DECL) {
3985 tmp = tmp->children;
3986 continue;
3987 }
3988 }
3989 if (tmp == node)
3990 break;
3991
3992 if (tmp->next != NULL) {
3993 tmp = tmp->next;
3994 continue;
3995 }
3996
3997 do {
3998 tmp = tmp->parent;
3999 if (tmp == NULL)
4000 break;
4001 if (tmp == node) {
4002 tmp = NULL;
4003 break;
4004 }
4005 if (tmp->next != NULL) {
4006 tmp = tmp->next;
4007 break;
4008 }
4009 } while (tmp != NULL);
4010 }
4011 return(ret);
4012}
4013
4014/**
4015 * xmlXPathStringHash:
4016 * @string: a string
4017 *
4018 * Function computing the beginning of the string value of the node,
4019 * used to speed up comparisons
4020 *
4021 * Returns an int usable as a hash
4022 */
4023static unsigned int
4024xmlXPathStringHash(const xmlChar * string) {
4025 if (string == NULL)
4026 return((unsigned int) 0);
4027 if (string[0] == 0)
4028 return(0);
4029 return(((unsigned int) string[0]) +
4030 (((unsigned int) string[1]) << 8));
4031}
4032
4033/**
Owen Taylor3473f882001-02-23 17:55:21 +00004034 * xmlXPathCompareNodeSetFloat:
4035 * @ctxt: the XPath Parser context
4036 * @inf: less than (1) or greater than (0)
4037 * @strict: is the comparison strict
4038 * @arg: the node set
4039 * @f: the value
4040 *
4041 * Implement the compare operation between a nodeset and a number
4042 * @ns < @val (1, 1, ...
4043 * @ns <= @val (1, 0, ...
4044 * @ns > @val (0, 1, ...
4045 * @ns >= @val (0, 0, ...
4046 *
4047 * If one object to be compared is a node-set and the other is a number,
4048 * then the comparison will be true if and only if there is a node in the
4049 * node-set such that the result of performing the comparison on the number
4050 * to be compared and on the result of converting the string-value of that
4051 * node to a number using the number function is true.
4052 *
4053 * Returns 0 or 1 depending on the results of the test.
4054 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004055static int
Owen Taylor3473f882001-02-23 17:55:21 +00004056xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
4057 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
4058 int i, ret = 0;
4059 xmlNodeSetPtr ns;
4060 xmlChar *str2;
4061
4062 if ((f == NULL) || (arg == NULL) ||
4063 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4064 xmlXPathFreeObject(arg);
4065 xmlXPathFreeObject(f);
4066 return(0);
4067 }
4068 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004069 if (ns != NULL) {
4070 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004071 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004072 if (str2 != NULL) {
4073 valuePush(ctxt,
4074 xmlXPathNewString(str2));
4075 xmlFree(str2);
4076 xmlXPathNumberFunction(ctxt, 1);
4077 valuePush(ctxt, xmlXPathObjectCopy(f));
4078 ret = xmlXPathCompareValues(ctxt, inf, strict);
4079 if (ret)
4080 break;
4081 }
4082 }
Owen Taylor3473f882001-02-23 17:55:21 +00004083 }
4084 xmlXPathFreeObject(arg);
4085 xmlXPathFreeObject(f);
4086 return(ret);
4087}
4088
4089/**
4090 * xmlXPathCompareNodeSetString:
4091 * @ctxt: the XPath Parser context
4092 * @inf: less than (1) or greater than (0)
4093 * @strict: is the comparison strict
4094 * @arg: the node set
4095 * @s: the value
4096 *
4097 * Implement the compare operation between a nodeset and a string
4098 * @ns < @val (1, 1, ...
4099 * @ns <= @val (1, 0, ...
4100 * @ns > @val (0, 1, ...
4101 * @ns >= @val (0, 0, ...
4102 *
4103 * If one object to be compared is a node-set and the other is a string,
4104 * then the comparison will be true if and only if there is a node in
4105 * the node-set such that the result of performing the comparison on the
4106 * string-value of the node and the other string is true.
4107 *
4108 * Returns 0 or 1 depending on the results of the test.
4109 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004110static int
Owen Taylor3473f882001-02-23 17:55:21 +00004111xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
4112 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
4113 int i, ret = 0;
4114 xmlNodeSetPtr ns;
4115 xmlChar *str2;
4116
4117 if ((s == NULL) || (arg == NULL) ||
4118 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4119 xmlXPathFreeObject(arg);
4120 xmlXPathFreeObject(s);
4121 return(0);
4122 }
4123 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004124 if (ns != NULL) {
4125 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004126 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004127 if (str2 != NULL) {
4128 valuePush(ctxt,
4129 xmlXPathNewString(str2));
4130 xmlFree(str2);
4131 valuePush(ctxt, xmlXPathObjectCopy(s));
4132 ret = xmlXPathCompareValues(ctxt, inf, strict);
4133 if (ret)
4134 break;
4135 }
4136 }
Owen Taylor3473f882001-02-23 17:55:21 +00004137 }
4138 xmlXPathFreeObject(arg);
4139 xmlXPathFreeObject(s);
4140 return(ret);
4141}
4142
4143/**
4144 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004145 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00004146 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004147 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00004148 * @arg2: the second node set object
4149 *
4150 * Implement the compare operation on nodesets:
4151 *
4152 * If both objects to be compared are node-sets, then the comparison
4153 * will be true if and only if there is a node in the first node-set
4154 * and a node in the second node-set such that the result of performing
4155 * the comparison on the string-values of the two nodes is true.
4156 * ....
4157 * When neither object to be compared is a node-set and the operator
4158 * is <=, <, >= or >, then the objects are compared by converting both
4159 * objects to numbers and comparing the numbers according to IEEE 754.
4160 * ....
4161 * The number function converts its argument to a number as follows:
4162 * - a string that consists of optional whitespace followed by an
4163 * optional minus sign followed by a Number followed by whitespace
4164 * is converted to the IEEE 754 number that is nearest (according
4165 * to the IEEE 754 round-to-nearest rule) to the mathematical value
4166 * represented by the string; any other string is converted to NaN
4167 *
4168 * Conclusion all nodes need to be converted first to their string value
4169 * and then the comparison must be done when possible
4170 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004171static int
4172xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00004173 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4174 int i, j, init = 0;
4175 double val1;
4176 double *values2;
4177 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004178 xmlNodeSetPtr ns1;
4179 xmlNodeSetPtr ns2;
4180
4181 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004182 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4183 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004184 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004185 }
Owen Taylor3473f882001-02-23 17:55:21 +00004186 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004187 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4188 xmlXPathFreeObject(arg1);
4189 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004190 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004191 }
Owen Taylor3473f882001-02-23 17:55:21 +00004192
4193 ns1 = arg1->nodesetval;
4194 ns2 = arg2->nodesetval;
4195
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004196 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004197 xmlXPathFreeObject(arg1);
4198 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004199 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004200 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004201 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004202 xmlXPathFreeObject(arg1);
4203 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004204 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004205 }
Owen Taylor3473f882001-02-23 17:55:21 +00004206
4207 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4208 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004209 xmlXPathFreeObject(arg1);
4210 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004211 return(0);
4212 }
4213 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004214 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004215 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004216 continue;
4217 for (j = 0;j < ns2->nodeNr;j++) {
4218 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004219 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004220 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004221 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004222 continue;
4223 if (inf && strict)
4224 ret = (val1 < values2[j]);
4225 else if (inf && !strict)
4226 ret = (val1 <= values2[j]);
4227 else if (!inf && strict)
4228 ret = (val1 > values2[j]);
4229 else if (!inf && !strict)
4230 ret = (val1 >= values2[j]);
4231 if (ret)
4232 break;
4233 }
4234 if (ret)
4235 break;
4236 init = 1;
4237 }
4238 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004239 xmlXPathFreeObject(arg1);
4240 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004241 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004242}
4243
4244/**
4245 * xmlXPathCompareNodeSetValue:
4246 * @ctxt: the XPath Parser context
4247 * @inf: less than (1) or greater than (0)
4248 * @strict: is the comparison strict
4249 * @arg: the node set
4250 * @val: the value
4251 *
4252 * Implement the compare operation between a nodeset and a value
4253 * @ns < @val (1, 1, ...
4254 * @ns <= @val (1, 0, ...
4255 * @ns > @val (0, 1, ...
4256 * @ns >= @val (0, 0, ...
4257 *
4258 * If one object to be compared is a node-set and the other is a boolean,
4259 * then the comparison will be true if and only if the result of performing
4260 * the comparison on the boolean and on the result of converting
4261 * the node-set to a boolean using the boolean function is true.
4262 *
4263 * Returns 0 or 1 depending on the results of the test.
4264 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004265static int
Owen Taylor3473f882001-02-23 17:55:21 +00004266xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4267 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4268 if ((val == NULL) || (arg == NULL) ||
4269 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4270 return(0);
4271
4272 switch(val->type) {
4273 case XPATH_NUMBER:
4274 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4275 case XPATH_NODESET:
4276 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004277 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004278 case XPATH_STRING:
4279 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4280 case XPATH_BOOLEAN:
4281 valuePush(ctxt, arg);
4282 xmlXPathBooleanFunction(ctxt, 1);
4283 valuePush(ctxt, val);
4284 return(xmlXPathCompareValues(ctxt, inf, strict));
4285 default:
4286 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004287 }
4288 return(0);
4289}
4290
4291/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004292 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00004293 * @arg: the nodeset object argument
4294 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00004295 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004296 *
4297 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4298 * If one object to be compared is a node-set and the other is a string,
4299 * then the comparison will be true if and only if there is a node in
4300 * the node-set such that the result of performing the comparison on the
4301 * string-value of the node and the other string is true.
4302 *
4303 * Returns 0 or 1 depending on the results of the test.
4304 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004305static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004306xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004307{
Owen Taylor3473f882001-02-23 17:55:21 +00004308 int i;
4309 xmlNodeSetPtr ns;
4310 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004311 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004312
4313 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004314 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4315 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004316 ns = arg->nodesetval;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004317 hash = xmlXPathStringHash(str);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004318 if (ns == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004319 return (0);
Daniel Veillard73c9c042001-07-05 20:02:54 +00004320 if (ns->nodeNr <= 0) {
4321 if (hash == 0)
William M. Brack0c022ad2002-07-12 00:56:01 +00004322 return(neq ^ 1);
4323 return(neq);
Daniel Veillard73c9c042001-07-05 20:02:54 +00004324 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004325 for (i = 0; i < ns->nodeNr; i++) {
4326 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4327 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4328 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4329 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004330 if (neq)
4331 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004332 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00004333 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
4334 if (neq)
4335 continue;
4336 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00004337 } else if (neq) {
4338 if (str2 != NULL)
4339 xmlFree(str2);
4340 return (1);
4341 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004342 if (str2 != NULL)
4343 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004344 } else if (neq)
4345 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00004346 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004347 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004348}
4349
4350/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004351 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00004352 * @arg: the nodeset object argument
4353 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00004354 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004355 *
4356 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4357 * If one object to be compared is a node-set and the other is a number,
4358 * then the comparison will be true if and only if there is a node in
4359 * the node-set such that the result of performing the comparison on the
4360 * number to be compared and on the result of converting the string-value
4361 * of that node to a number using the number function is true.
4362 *
4363 * Returns 0 or 1 depending on the results of the test.
4364 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004365static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004366xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
4367 xmlXPathObjectPtr arg, double f, int neq) {
4368 int i, ret=0;
4369 xmlNodeSetPtr ns;
4370 xmlChar *str2;
4371 xmlXPathObjectPtr val;
4372 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00004373
4374 if ((arg == NULL) ||
4375 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4376 return(0);
4377
William M. Brack0c022ad2002-07-12 00:56:01 +00004378 ns = arg->nodesetval;
4379 if (ns != NULL) {
4380 for (i=0;i<ns->nodeNr;i++) {
4381 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4382 if (str2 != NULL) {
4383 valuePush(ctxt, xmlXPathNewString(str2));
4384 xmlFree(str2);
4385 xmlXPathNumberFunction(ctxt, 1);
4386 val = valuePop(ctxt);
4387 v = val->floatval;
4388 xmlXPathFreeObject(val);
4389 if (!xmlXPathIsNaN(v)) {
4390 if ((!neq) && (v==f)) {
4391 ret = 1;
4392 break;
4393 } else if ((neq) && (v!=f)) {
4394 ret = 1;
4395 break;
4396 }
4397 }
4398 }
4399 }
4400 }
4401
4402 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004403}
4404
4405
4406/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004407 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00004408 * @arg1: first nodeset object argument
4409 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00004410 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004411 *
William M. Brack0c022ad2002-07-12 00:56:01 +00004412 * Implement the equal / not equal operation on XPath nodesets:
4413 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00004414 * If both objects to be compared are node-sets, then the comparison
4415 * will be true if and only if there is a node in the first node-set and
4416 * a node in the second node-set such that the result of performing the
4417 * comparison on the string-values of the two nodes is true.
4418 *
4419 * (needless to say, this is a costly operation)
4420 *
4421 * Returns 0 or 1 depending on the results of the test.
4422 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004423static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004424xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00004425 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004426 unsigned int *hashs1;
4427 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004428 xmlChar **values1;
4429 xmlChar **values2;
4430 int ret = 0;
4431 xmlNodeSetPtr ns1;
4432 xmlNodeSetPtr ns2;
4433
4434 if ((arg1 == NULL) ||
4435 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4436 return(0);
4437 if ((arg2 == NULL) ||
4438 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4439 return(0);
4440
4441 ns1 = arg1->nodesetval;
4442 ns2 = arg2->nodesetval;
4443
Daniel Veillard911f49a2001-04-07 15:39:35 +00004444 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004445 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004446 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004447 return(0);
4448
4449 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00004450 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00004451 */
William M. Brack0c022ad2002-07-12 00:56:01 +00004452 if (neq == 0)
4453 for (i = 0;i < ns1->nodeNr;i++)
4454 for (j = 0;j < ns2->nodeNr;j++)
4455 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4456 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00004457
4458 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
4459 if (values1 == NULL)
4460 return(0);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004461 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4462 if (hashs1 == NULL) {
4463 xmlFree(values1);
4464 return(0);
4465 }
Owen Taylor3473f882001-02-23 17:55:21 +00004466 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4467 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4468 if (values2 == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004469 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004470 xmlFree(values1);
4471 return(0);
4472 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004473 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4474 if (hashs2 == NULL) {
4475 xmlFree(hashs1);
4476 xmlFree(values1);
4477 xmlFree(values2);
4478 return(0);
4479 }
Owen Taylor3473f882001-02-23 17:55:21 +00004480 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4481 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004482 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004483 for (j = 0;j < ns2->nodeNr;j++) {
4484 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004485 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004486 if (hashs1[i] != hashs2[j]) {
4487 if (neq) {
4488 ret = 1;
4489 break;
4490 }
4491 }
4492 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004493 if (values1[i] == NULL)
4494 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4495 if (values2[j] == NULL)
4496 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004497 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004498 if (ret)
4499 break;
4500 }
Owen Taylor3473f882001-02-23 17:55:21 +00004501 }
4502 if (ret)
4503 break;
4504 }
4505 for (i = 0;i < ns1->nodeNr;i++)
4506 if (values1[i] != NULL)
4507 xmlFree(values1[i]);
4508 for (j = 0;j < ns2->nodeNr;j++)
4509 if (values2[j] != NULL)
4510 xmlFree(values2[j]);
4511 xmlFree(values1);
4512 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004513 xmlFree(hashs1);
4514 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004515 return(ret);
4516}
4517
William M. Brack0c022ad2002-07-12 00:56:01 +00004518static int
4519xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
4520 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00004521 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00004522 /*
4523 *At this point we are assured neither arg1 nor arg2
4524 *is a nodeset, so we can just pick the appropriate routine.
4525 */
Owen Taylor3473f882001-02-23 17:55:21 +00004526 switch (arg1->type) {
4527 case XPATH_UNDEFINED:
4528#ifdef DEBUG_EXPR
4529 xmlGenericError(xmlGenericErrorContext,
4530 "Equal: undefined\n");
4531#endif
4532 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004533 case XPATH_BOOLEAN:
4534 switch (arg2->type) {
4535 case XPATH_UNDEFINED:
4536#ifdef DEBUG_EXPR
4537 xmlGenericError(xmlGenericErrorContext,
4538 "Equal: undefined\n");
4539#endif
4540 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004541 case XPATH_BOOLEAN:
4542#ifdef DEBUG_EXPR
4543 xmlGenericError(xmlGenericErrorContext,
4544 "Equal: %d boolean %d \n",
4545 arg1->boolval, arg2->boolval);
4546#endif
4547 ret = (arg1->boolval == arg2->boolval);
4548 break;
4549 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00004550 ret = (arg1->boolval ==
4551 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004552 break;
4553 case XPATH_STRING:
4554 if ((arg2->stringval == NULL) ||
4555 (arg2->stringval[0] == 0)) ret = 0;
4556 else
4557 ret = 1;
4558 ret = (arg1->boolval == ret);
4559 break;
4560 case XPATH_USERS:
4561 case XPATH_POINT:
4562 case XPATH_RANGE:
4563 case XPATH_LOCATIONSET:
4564 TODO
4565 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004566 case XPATH_NODESET:
4567 case XPATH_XSLT_TREE:
4568 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004569 }
4570 break;
4571 case XPATH_NUMBER:
4572 switch (arg2->type) {
4573 case XPATH_UNDEFINED:
4574#ifdef DEBUG_EXPR
4575 xmlGenericError(xmlGenericErrorContext,
4576 "Equal: undefined\n");
4577#endif
4578 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004579 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00004580 ret = (arg2->boolval==
4581 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004582 break;
4583 case XPATH_STRING:
4584 valuePush(ctxt, arg2);
4585 xmlXPathNumberFunction(ctxt, 1);
4586 arg2 = valuePop(ctxt);
4587 /* no break on purpose */
4588 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004589 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004590 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4591 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004592 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4593 if (xmlXPathIsInf(arg2->floatval) == 1)
4594 ret = 1;
4595 else
4596 ret = 0;
4597 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4598 if (xmlXPathIsInf(arg2->floatval) == -1)
4599 ret = 1;
4600 else
4601 ret = 0;
4602 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4603 if (xmlXPathIsInf(arg1->floatval) == 1)
4604 ret = 1;
4605 else
4606 ret = 0;
4607 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4608 if (xmlXPathIsInf(arg1->floatval) == -1)
4609 ret = 1;
4610 else
4611 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004612 } else {
4613 ret = (arg1->floatval == arg2->floatval);
4614 }
Owen Taylor3473f882001-02-23 17:55:21 +00004615 break;
4616 case XPATH_USERS:
4617 case XPATH_POINT:
4618 case XPATH_RANGE:
4619 case XPATH_LOCATIONSET:
4620 TODO
4621 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004622 case XPATH_NODESET:
4623 case XPATH_XSLT_TREE:
4624 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004625 }
4626 break;
4627 case XPATH_STRING:
4628 switch (arg2->type) {
4629 case XPATH_UNDEFINED:
4630#ifdef DEBUG_EXPR
4631 xmlGenericError(xmlGenericErrorContext,
4632 "Equal: undefined\n");
4633#endif
4634 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004635 case XPATH_BOOLEAN:
4636 if ((arg1->stringval == NULL) ||
4637 (arg1->stringval[0] == 0)) ret = 0;
4638 else
4639 ret = 1;
4640 ret = (arg2->boolval == ret);
4641 break;
4642 case XPATH_STRING:
4643 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4644 break;
4645 case XPATH_NUMBER:
4646 valuePush(ctxt, arg1);
4647 xmlXPathNumberFunction(ctxt, 1);
4648 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004649 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004650 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4651 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004652 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4653 if (xmlXPathIsInf(arg2->floatval) == 1)
4654 ret = 1;
4655 else
4656 ret = 0;
4657 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4658 if (xmlXPathIsInf(arg2->floatval) == -1)
4659 ret = 1;
4660 else
4661 ret = 0;
4662 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4663 if (xmlXPathIsInf(arg1->floatval) == 1)
4664 ret = 1;
4665 else
4666 ret = 0;
4667 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4668 if (xmlXPathIsInf(arg1->floatval) == -1)
4669 ret = 1;
4670 else
4671 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004672 } else {
4673 ret = (arg1->floatval == arg2->floatval);
4674 }
Owen Taylor3473f882001-02-23 17:55:21 +00004675 break;
4676 case XPATH_USERS:
4677 case XPATH_POINT:
4678 case XPATH_RANGE:
4679 case XPATH_LOCATIONSET:
4680 TODO
4681 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004682 case XPATH_NODESET:
4683 case XPATH_XSLT_TREE:
4684 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004685 }
4686 break;
4687 case XPATH_USERS:
4688 case XPATH_POINT:
4689 case XPATH_RANGE:
4690 case XPATH_LOCATIONSET:
4691 TODO
4692 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004693 case XPATH_NODESET:
4694 case XPATH_XSLT_TREE:
4695 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004696 }
4697 xmlXPathFreeObject(arg1);
4698 xmlXPathFreeObject(arg2);
4699 return(ret);
4700}
4701
William M. Brack0c022ad2002-07-12 00:56:01 +00004702/**
4703 * xmlXPathEqualValues:
4704 * @ctxt: the XPath Parser context
4705 *
4706 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4707 *
4708 * Returns 0 or 1 depending on the results of the test.
4709 */
4710int
4711xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4712 xmlXPathObjectPtr arg1, arg2, argtmp;
4713 int ret = 0;
4714
4715 arg2 = valuePop(ctxt);
4716 arg1 = valuePop(ctxt);
4717 if ((arg1 == NULL) || (arg2 == NULL)) {
4718 if (arg1 != NULL)
4719 xmlXPathFreeObject(arg1);
4720 else
4721 xmlXPathFreeObject(arg2);
4722 XP_ERROR0(XPATH_INVALID_OPERAND);
4723 }
4724
4725 if (arg1 == arg2) {
4726#ifdef DEBUG_EXPR
4727 xmlGenericError(xmlGenericErrorContext,
4728 "Equal: by pointer\n");
4729#endif
4730 return(1);
4731 }
4732
4733 /*
4734 *If either argument is a nodeset, it's a 'special case'
4735 */
4736 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4737 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4738 /*
4739 *Hack it to assure arg1 is the nodeset
4740 */
4741 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4742 argtmp = arg2;
4743 arg2 = arg1;
4744 arg1 = argtmp;
4745 }
4746 switch (arg2->type) {
4747 case XPATH_UNDEFINED:
4748#ifdef DEBUG_EXPR
4749 xmlGenericError(xmlGenericErrorContext,
4750 "Equal: undefined\n");
4751#endif
4752 break;
4753 case XPATH_NODESET:
4754 case XPATH_XSLT_TREE:
4755 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
4756 break;
4757 case XPATH_BOOLEAN:
4758 if ((arg1->nodesetval == NULL) ||
4759 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4760 else
4761 ret = 1;
4762 ret = (ret == arg2->boolval);
4763 break;
4764 case XPATH_NUMBER:
4765 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
4766 break;
4767 case XPATH_STRING:
4768 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
4769 break;
4770 case XPATH_USERS:
4771 case XPATH_POINT:
4772 case XPATH_RANGE:
4773 case XPATH_LOCATIONSET:
4774 TODO
4775 break;
4776 }
4777 xmlXPathFreeObject(arg1);
4778 xmlXPathFreeObject(arg2);
4779 return(ret);
4780 }
4781
4782 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4783}
4784
4785/**
4786 * xmlXPathNotEqualValues:
4787 * @ctxt: the XPath Parser context
4788 *
4789 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4790 *
4791 * Returns 0 or 1 depending on the results of the test.
4792 */
4793int
4794xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
4795 xmlXPathObjectPtr arg1, arg2, argtmp;
4796 int ret = 0;
4797
4798 arg2 = valuePop(ctxt);
4799 arg1 = valuePop(ctxt);
4800 if ((arg1 == NULL) || (arg2 == NULL)) {
4801 if (arg1 != NULL)
4802 xmlXPathFreeObject(arg1);
4803 else
4804 xmlXPathFreeObject(arg2);
4805 XP_ERROR0(XPATH_INVALID_OPERAND);
4806 }
4807
4808 if (arg1 == arg2) {
4809#ifdef DEBUG_EXPR
4810 xmlGenericError(xmlGenericErrorContext,
4811 "NotEqual: by pointer\n");
4812#endif
4813 return(0);
4814 }
4815
4816 /*
4817 *If either argument is a nodeset, it's a 'special case'
4818 */
4819 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4820 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4821 /*
4822 *Hack it to assure arg1 is the nodeset
4823 */
4824 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4825 argtmp = arg2;
4826 arg2 = arg1;
4827 arg1 = argtmp;
4828 }
4829 switch (arg2->type) {
4830 case XPATH_UNDEFINED:
4831#ifdef DEBUG_EXPR
4832 xmlGenericError(xmlGenericErrorContext,
4833 "NotEqual: undefined\n");
4834#endif
4835 break;
4836 case XPATH_NODESET:
4837 case XPATH_XSLT_TREE:
4838 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
4839 break;
4840 case XPATH_BOOLEAN:
4841 if ((arg1->nodesetval == NULL) ||
4842 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4843 else
4844 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00004845 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00004846 break;
4847 case XPATH_NUMBER:
4848 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
4849 break;
4850 case XPATH_STRING:
4851 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
4852 break;
4853 case XPATH_USERS:
4854 case XPATH_POINT:
4855 case XPATH_RANGE:
4856 case XPATH_LOCATIONSET:
4857 TODO
4858 break;
4859 }
4860 xmlXPathFreeObject(arg1);
4861 xmlXPathFreeObject(arg2);
4862 return(ret);
4863 }
4864
4865 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4866}
Owen Taylor3473f882001-02-23 17:55:21 +00004867
4868/**
4869 * xmlXPathCompareValues:
4870 * @ctxt: the XPath Parser context
4871 * @inf: less than (1) or greater than (0)
4872 * @strict: is the comparison strict
4873 *
4874 * Implement the compare operation on XPath objects:
4875 * @arg1 < @arg2 (1, 1, ...
4876 * @arg1 <= @arg2 (1, 0, ...
4877 * @arg1 > @arg2 (0, 1, ...
4878 * @arg1 >= @arg2 (0, 0, ...
4879 *
4880 * When neither object to be compared is a node-set and the operator is
4881 * <=, <, >=, >, then the objects are compared by converted both objects
4882 * to numbers and comparing the numbers according to IEEE 754. The <
4883 * comparison will be true if and only if the first number is less than the
4884 * second number. The <= comparison will be true if and only if the first
4885 * number is less than or equal to the second number. The > comparison
4886 * will be true if and only if the first number is greater than the second
4887 * number. The >= comparison will be true if and only if the first number
4888 * is greater than or equal to the second number.
4889 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004890 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00004891 */
4892int
4893xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004894 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004895 xmlXPathObjectPtr arg1, arg2;
4896
William M. Brack0c022ad2002-07-12 00:56:01 +00004897 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00004898 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00004899 if ((arg1 == NULL) || (arg2 == NULL)) {
4900 if (arg1 != NULL)
4901 xmlXPathFreeObject(arg1);
4902 else
4903 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004904 XP_ERROR0(XPATH_INVALID_OPERAND);
4905 }
4906
William M. Brack0c022ad2002-07-12 00:56:01 +00004907 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4908 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4909 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
4910 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004911 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004912 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00004913 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004914 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
4915 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004916 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004917 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
4918 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00004919 }
4920 }
4921 return(ret);
4922 }
4923
4924 if (arg1->type != XPATH_NUMBER) {
4925 valuePush(ctxt, arg1);
4926 xmlXPathNumberFunction(ctxt, 1);
4927 arg1 = valuePop(ctxt);
4928 }
4929 if (arg1->type != XPATH_NUMBER) {
4930 xmlXPathFreeObject(arg1);
4931 xmlXPathFreeObject(arg2);
4932 XP_ERROR0(XPATH_INVALID_OPERAND);
4933 }
4934 if (arg2->type != XPATH_NUMBER) {
4935 valuePush(ctxt, arg2);
4936 xmlXPathNumberFunction(ctxt, 1);
4937 arg2 = valuePop(ctxt);
4938 }
4939 if (arg2->type != XPATH_NUMBER) {
4940 xmlXPathFreeObject(arg1);
4941 xmlXPathFreeObject(arg2);
4942 XP_ERROR0(XPATH_INVALID_OPERAND);
4943 }
4944 /*
4945 * Add tests for infinity and nan
4946 * => feedback on 3.4 for Inf and NaN
4947 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004948 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00004949 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004950 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004951 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004952 arg1i=xmlXPathIsInf(arg1->floatval);
4953 arg2i=xmlXPathIsInf(arg2->floatval);
4954 if (inf && strict) {
4955 if ((arg1i == -1 && arg2i != -1) ||
4956 (arg2i == 1 && arg1i != 1)) {
4957 ret = 1;
4958 } else if (arg1i == 0 && arg2i == 0) {
4959 ret = (arg1->floatval < arg2->floatval);
4960 } else {
4961 ret = 0;
4962 }
4963 }
4964 else if (inf && !strict) {
4965 if (arg1i == -1 || arg2i == 1) {
4966 ret = 1;
4967 } else if (arg1i == 0 && arg2i == 0) {
4968 ret = (arg1->floatval <= arg2->floatval);
4969 } else {
4970 ret = 0;
4971 }
4972 }
4973 else if (!inf && strict) {
4974 if ((arg1i == 1 && arg2i != 1) ||
4975 (arg2i == -1 && arg1i != -1)) {
4976 ret = 1;
4977 } else if (arg1i == 0 && arg2i == 0) {
4978 ret = (arg1->floatval > arg2->floatval);
4979 } else {
4980 ret = 0;
4981 }
4982 }
4983 else if (!inf && !strict) {
4984 if (arg1i == 1 || arg2i == -1) {
4985 ret = 1;
4986 } else if (arg1i == 0 && arg2i == 0) {
4987 ret = (arg1->floatval >= arg2->floatval);
4988 } else {
4989 ret = 0;
4990 }
4991 }
Daniel Veillard21458c82002-03-27 16:12:22 +00004992 }
Owen Taylor3473f882001-02-23 17:55:21 +00004993 xmlXPathFreeObject(arg1);
4994 xmlXPathFreeObject(arg2);
4995 return(ret);
4996}
4997
4998/**
4999 * xmlXPathValueFlipSign:
5000 * @ctxt: the XPath Parser context
5001 *
5002 * Implement the unary - operation on an XPath object
5003 * The numeric operators convert their operands to numbers as if
5004 * by calling the number function.
5005 */
5006void
5007xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005008 CAST_TO_NUMBER;
5009 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005010 if (xmlXPathIsNaN(ctxt->value->floatval))
5011 ctxt->value->floatval=xmlXPathNAN;
5012 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
5013 ctxt->value->floatval=xmlXPathNINF;
5014 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
5015 ctxt->value->floatval=xmlXPathPINF;
5016 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005017 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
5018 ctxt->value->floatval = xmlXPathNZERO;
5019 else
5020 ctxt->value->floatval = 0;
5021 }
5022 else
5023 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00005024}
5025
5026/**
5027 * xmlXPathAddValues:
5028 * @ctxt: the XPath Parser context
5029 *
5030 * Implement the add operation on XPath objects:
5031 * The numeric operators convert their operands to numbers as if
5032 * by calling the number function.
5033 */
5034void
5035xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
5036 xmlXPathObjectPtr arg;
5037 double val;
5038
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005039 arg = valuePop(ctxt);
5040 if (arg == NULL)
5041 XP_ERROR(XPATH_INVALID_OPERAND);
5042 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005043 xmlXPathFreeObject(arg);
5044
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005045 CAST_TO_NUMBER;
5046 CHECK_TYPE(XPATH_NUMBER);
5047 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00005048}
5049
5050/**
5051 * xmlXPathSubValues:
5052 * @ctxt: the XPath Parser context
5053 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005054 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00005055 * The numeric operators convert their operands to numbers as if
5056 * by calling the number function.
5057 */
5058void
5059xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
5060 xmlXPathObjectPtr arg;
5061 double val;
5062
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005063 arg = valuePop(ctxt);
5064 if (arg == NULL)
5065 XP_ERROR(XPATH_INVALID_OPERAND);
5066 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005067 xmlXPathFreeObject(arg);
5068
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005069 CAST_TO_NUMBER;
5070 CHECK_TYPE(XPATH_NUMBER);
5071 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005072}
5073
5074/**
5075 * xmlXPathMultValues:
5076 * @ctxt: the XPath Parser context
5077 *
5078 * Implement the multiply operation on XPath objects:
5079 * The numeric operators convert their operands to numbers as if
5080 * by calling the number function.
5081 */
5082void
5083xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
5084 xmlXPathObjectPtr arg;
5085 double val;
5086
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005087 arg = valuePop(ctxt);
5088 if (arg == NULL)
5089 XP_ERROR(XPATH_INVALID_OPERAND);
5090 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005091 xmlXPathFreeObject(arg);
5092
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005093 CAST_TO_NUMBER;
5094 CHECK_TYPE(XPATH_NUMBER);
5095 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005096}
5097
5098/**
5099 * xmlXPathDivValues:
5100 * @ctxt: the XPath Parser context
5101 *
5102 * Implement the div operation on XPath objects @arg1 / @arg2:
5103 * The numeric operators convert their operands to numbers as if
5104 * by calling the number function.
5105 */
5106void
5107xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
5108 xmlXPathObjectPtr arg;
5109 double val;
5110
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005111 arg = valuePop(ctxt);
5112 if (arg == NULL)
5113 XP_ERROR(XPATH_INVALID_OPERAND);
5114 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005115 xmlXPathFreeObject(arg);
5116
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005117 CAST_TO_NUMBER;
5118 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005119 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
5120 ctxt->value->floatval = xmlXPathNAN;
5121 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005122 if (ctxt->value->floatval == 0)
5123 ctxt->value->floatval = xmlXPathNAN;
5124 else if (ctxt->value->floatval > 0)
5125 ctxt->value->floatval = xmlXPathNINF;
5126 else if (ctxt->value->floatval < 0)
5127 ctxt->value->floatval = xmlXPathPINF;
5128 }
5129 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00005130 if (ctxt->value->floatval == 0)
5131 ctxt->value->floatval = xmlXPathNAN;
5132 else if (ctxt->value->floatval > 0)
5133 ctxt->value->floatval = xmlXPathPINF;
5134 else if (ctxt->value->floatval < 0)
5135 ctxt->value->floatval = xmlXPathNINF;
5136 } else
5137 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005138}
5139
5140/**
5141 * xmlXPathModValues:
5142 * @ctxt: the XPath Parser context
5143 *
5144 * Implement the mod operation on XPath objects: @arg1 / @arg2
5145 * The numeric operators convert their operands to numbers as if
5146 * by calling the number function.
5147 */
5148void
5149xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
5150 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005151 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00005152
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005153 arg = valuePop(ctxt);
5154 if (arg == NULL)
5155 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005156 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005157 xmlXPathFreeObject(arg);
5158
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005159 CAST_TO_NUMBER;
5160 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005161 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00005162 if (arg2 == 0)
5163 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005164 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00005165 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005166 }
Owen Taylor3473f882001-02-23 17:55:21 +00005167}
5168
5169/************************************************************************
5170 * *
5171 * The traversal functions *
5172 * *
5173 ************************************************************************/
5174
Owen Taylor3473f882001-02-23 17:55:21 +00005175/*
5176 * A traversal function enumerates nodes along an axis.
5177 * Initially it must be called with NULL, and it indicates
5178 * termination on the axis by returning NULL.
5179 */
5180typedef xmlNodePtr (*xmlXPathTraversalFunction)
5181 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
5182
5183/**
5184 * xmlXPathNextSelf:
5185 * @ctxt: the XPath Parser context
5186 * @cur: the current node in the traversal
5187 *
5188 * Traversal function for the "self" direction
5189 * The self axis contains just the context node itself
5190 *
5191 * Returns the next element following that axis
5192 */
5193xmlNodePtr
5194xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5195 if (cur == NULL)
5196 return(ctxt->context->node);
5197 return(NULL);
5198}
5199
5200/**
5201 * xmlXPathNextChild:
5202 * @ctxt: the XPath Parser context
5203 * @cur: the current node in the traversal
5204 *
5205 * Traversal function for the "child" direction
5206 * The child axis contains the children of the context node in document order.
5207 *
5208 * Returns the next element following that axis
5209 */
5210xmlNodePtr
5211xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5212 if (cur == NULL) {
5213 if (ctxt->context->node == NULL) return(NULL);
5214 switch (ctxt->context->node->type) {
5215 case XML_ELEMENT_NODE:
5216 case XML_TEXT_NODE:
5217 case XML_CDATA_SECTION_NODE:
5218 case XML_ENTITY_REF_NODE:
5219 case XML_ENTITY_NODE:
5220 case XML_PI_NODE:
5221 case XML_COMMENT_NODE:
5222 case XML_NOTATION_NODE:
5223 case XML_DTD_NODE:
5224 return(ctxt->context->node->children);
5225 case XML_DOCUMENT_NODE:
5226 case XML_DOCUMENT_TYPE_NODE:
5227 case XML_DOCUMENT_FRAG_NODE:
5228 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005229#ifdef LIBXML_DOCB_ENABLED
5230 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005231#endif
5232 return(((xmlDocPtr) ctxt->context->node)->children);
5233 case XML_ELEMENT_DECL:
5234 case XML_ATTRIBUTE_DECL:
5235 case XML_ENTITY_DECL:
5236 case XML_ATTRIBUTE_NODE:
5237 case XML_NAMESPACE_DECL:
5238 case XML_XINCLUDE_START:
5239 case XML_XINCLUDE_END:
5240 return(NULL);
5241 }
5242 return(NULL);
5243 }
5244 if ((cur->type == XML_DOCUMENT_NODE) ||
5245 (cur->type == XML_HTML_DOCUMENT_NODE))
5246 return(NULL);
5247 return(cur->next);
5248}
5249
5250/**
5251 * xmlXPathNextDescendant:
5252 * @ctxt: the XPath Parser context
5253 * @cur: the current node in the traversal
5254 *
5255 * Traversal function for the "descendant" direction
5256 * the descendant axis contains the descendants of the context node in document
5257 * order; a descendant is a child or a child of a child and so on.
5258 *
5259 * Returns the next element following that axis
5260 */
5261xmlNodePtr
5262xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5263 if (cur == NULL) {
5264 if (ctxt->context->node == NULL)
5265 return(NULL);
5266 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5267 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5268 return(NULL);
5269
5270 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5271 return(ctxt->context->doc->children);
5272 return(ctxt->context->node->children);
5273 }
5274
Daniel Veillard567e1b42001-08-01 15:53:47 +00005275 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00005276 /*
5277 * Do not descend on entities declarations
5278 */
5279 if (cur->children->type != XML_ENTITY_DECL) {
5280 cur = cur->children;
5281 /*
5282 * Skip DTDs
5283 */
5284 if (cur->type != XML_DTD_NODE)
5285 return(cur);
5286 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00005287 }
5288
5289 if (cur == ctxt->context->node) return(NULL);
5290
Daniel Veillard68e9e742002-11-16 15:35:11 +00005291 while (cur->next != NULL) {
5292 cur = cur->next;
5293 if ((cur->type != XML_ENTITY_DECL) &&
5294 (cur->type != XML_DTD_NODE))
5295 return(cur);
5296 }
Owen Taylor3473f882001-02-23 17:55:21 +00005297
5298 do {
5299 cur = cur->parent;
5300 if (cur == NULL) return(NULL);
5301 if (cur == ctxt->context->node) return(NULL);
5302 if (cur->next != NULL) {
5303 cur = cur->next;
5304 return(cur);
5305 }
5306 } while (cur != NULL);
5307 return(cur);
5308}
5309
5310/**
5311 * xmlXPathNextDescendantOrSelf:
5312 * @ctxt: the XPath Parser context
5313 * @cur: the current node in the traversal
5314 *
5315 * Traversal function for the "descendant-or-self" direction
5316 * the descendant-or-self axis contains the context node and the descendants
5317 * of the context node in document order; thus the context node is the first
5318 * node on the axis, and the first child of the context node is the second node
5319 * on the axis
5320 *
5321 * Returns the next element following that axis
5322 */
5323xmlNodePtr
5324xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5325 if (cur == NULL) {
5326 if (ctxt->context->node == NULL)
5327 return(NULL);
5328 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5329 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5330 return(NULL);
5331 return(ctxt->context->node);
5332 }
5333
5334 return(xmlXPathNextDescendant(ctxt, cur));
5335}
5336
5337/**
5338 * xmlXPathNextParent:
5339 * @ctxt: the XPath Parser context
5340 * @cur: the current node in the traversal
5341 *
5342 * Traversal function for the "parent" direction
5343 * The parent axis contains the parent of the context node, if there is one.
5344 *
5345 * Returns the next element following that axis
5346 */
5347xmlNodePtr
5348xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5349 /*
5350 * the parent of an attribute or namespace node is the element
5351 * to which the attribute or namespace node is attached
5352 * Namespace handling !!!
5353 */
5354 if (cur == NULL) {
5355 if (ctxt->context->node == NULL) return(NULL);
5356 switch (ctxt->context->node->type) {
5357 case XML_ELEMENT_NODE:
5358 case XML_TEXT_NODE:
5359 case XML_CDATA_SECTION_NODE:
5360 case XML_ENTITY_REF_NODE:
5361 case XML_ENTITY_NODE:
5362 case XML_PI_NODE:
5363 case XML_COMMENT_NODE:
5364 case XML_NOTATION_NODE:
5365 case XML_DTD_NODE:
5366 case XML_ELEMENT_DECL:
5367 case XML_ATTRIBUTE_DECL:
5368 case XML_XINCLUDE_START:
5369 case XML_XINCLUDE_END:
5370 case XML_ENTITY_DECL:
5371 if (ctxt->context->node->parent == NULL)
5372 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005373 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005374 ((ctxt->context->node->parent->name[0] == ' ') ||
5375 (xmlStrEqual(ctxt->context->node->parent->name,
5376 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005377 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005378 return(ctxt->context->node->parent);
5379 case XML_ATTRIBUTE_NODE: {
5380 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5381
5382 return(att->parent);
5383 }
5384 case XML_DOCUMENT_NODE:
5385 case XML_DOCUMENT_TYPE_NODE:
5386 case XML_DOCUMENT_FRAG_NODE:
5387 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005388#ifdef LIBXML_DOCB_ENABLED
5389 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005390#endif
5391 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005392 case XML_NAMESPACE_DECL: {
5393 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5394
5395 if ((ns->next != NULL) &&
5396 (ns->next->type != XML_NAMESPACE_DECL))
5397 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005398 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005399 }
Owen Taylor3473f882001-02-23 17:55:21 +00005400 }
5401 }
5402 return(NULL);
5403}
5404
5405/**
5406 * xmlXPathNextAncestor:
5407 * @ctxt: the XPath Parser context
5408 * @cur: the current node in the traversal
5409 *
5410 * Traversal function for the "ancestor" direction
5411 * the ancestor axis contains the ancestors of the context node; the ancestors
5412 * of the context node consist of the parent of context node and the parent's
5413 * parent and so on; the nodes are ordered in reverse document order; thus the
5414 * parent is the first node on the axis, and the parent's parent is the second
5415 * node on the axis
5416 *
5417 * Returns the next element following that axis
5418 */
5419xmlNodePtr
5420xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5421 /*
5422 * the parent of an attribute or namespace node is the element
5423 * to which the attribute or namespace node is attached
5424 * !!!!!!!!!!!!!
5425 */
5426 if (cur == NULL) {
5427 if (ctxt->context->node == NULL) return(NULL);
5428 switch (ctxt->context->node->type) {
5429 case XML_ELEMENT_NODE:
5430 case XML_TEXT_NODE:
5431 case XML_CDATA_SECTION_NODE:
5432 case XML_ENTITY_REF_NODE:
5433 case XML_ENTITY_NODE:
5434 case XML_PI_NODE:
5435 case XML_COMMENT_NODE:
5436 case XML_DTD_NODE:
5437 case XML_ELEMENT_DECL:
5438 case XML_ATTRIBUTE_DECL:
5439 case XML_ENTITY_DECL:
5440 case XML_NOTATION_NODE:
5441 case XML_XINCLUDE_START:
5442 case XML_XINCLUDE_END:
5443 if (ctxt->context->node->parent == NULL)
5444 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005445 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005446 ((ctxt->context->node->parent->name[0] == ' ') ||
5447 (xmlStrEqual(ctxt->context->node->parent->name,
5448 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005449 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005450 return(ctxt->context->node->parent);
5451 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005452 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005453
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005454 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005455 }
5456 case XML_DOCUMENT_NODE:
5457 case XML_DOCUMENT_TYPE_NODE:
5458 case XML_DOCUMENT_FRAG_NODE:
5459 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005460#ifdef LIBXML_DOCB_ENABLED
5461 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005462#endif
5463 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005464 case XML_NAMESPACE_DECL: {
5465 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5466
5467 if ((ns->next != NULL) &&
5468 (ns->next->type != XML_NAMESPACE_DECL))
5469 return((xmlNodePtr) ns->next);
5470 /* Bad, how did that namespace ended-up there ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005471 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005472 }
Owen Taylor3473f882001-02-23 17:55:21 +00005473 }
5474 return(NULL);
5475 }
5476 if (cur == ctxt->context->doc->children)
5477 return((xmlNodePtr) ctxt->context->doc);
5478 if (cur == (xmlNodePtr) ctxt->context->doc)
5479 return(NULL);
5480 switch (cur->type) {
5481 case XML_ELEMENT_NODE:
5482 case XML_TEXT_NODE:
5483 case XML_CDATA_SECTION_NODE:
5484 case XML_ENTITY_REF_NODE:
5485 case XML_ENTITY_NODE:
5486 case XML_PI_NODE:
5487 case XML_COMMENT_NODE:
5488 case XML_NOTATION_NODE:
5489 case XML_DTD_NODE:
5490 case XML_ELEMENT_DECL:
5491 case XML_ATTRIBUTE_DECL:
5492 case XML_ENTITY_DECL:
5493 case XML_XINCLUDE_START:
5494 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005495 if (cur->parent == NULL)
5496 return(NULL);
5497 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005498 ((cur->parent->name[0] == ' ') ||
5499 (xmlStrEqual(cur->parent->name,
5500 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005501 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005502 return(cur->parent);
5503 case XML_ATTRIBUTE_NODE: {
5504 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5505
5506 return(att->parent);
5507 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005508 case XML_NAMESPACE_DECL: {
5509 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5510
5511 if ((ns->next != NULL) &&
5512 (ns->next->type != XML_NAMESPACE_DECL))
5513 return((xmlNodePtr) ns->next);
5514 /* Bad, how did that namespace ended-up there ? */
5515 return(NULL);
5516 }
Owen Taylor3473f882001-02-23 17:55:21 +00005517 case XML_DOCUMENT_NODE:
5518 case XML_DOCUMENT_TYPE_NODE:
5519 case XML_DOCUMENT_FRAG_NODE:
5520 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005521#ifdef LIBXML_DOCB_ENABLED
5522 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005523#endif
5524 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005525 }
5526 return(NULL);
5527}
5528
5529/**
5530 * xmlXPathNextAncestorOrSelf:
5531 * @ctxt: the XPath Parser context
5532 * @cur: the current node in the traversal
5533 *
5534 * Traversal function for the "ancestor-or-self" direction
5535 * he ancestor-or-self axis contains the context node and ancestors of
5536 * the context node in reverse document order; thus the context node is
5537 * the first node on the axis, and the context node's parent the second;
5538 * parent here is defined the same as with the parent axis.
5539 *
5540 * Returns the next element following that axis
5541 */
5542xmlNodePtr
5543xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5544 if (cur == NULL)
5545 return(ctxt->context->node);
5546 return(xmlXPathNextAncestor(ctxt, cur));
5547}
5548
5549/**
5550 * xmlXPathNextFollowingSibling:
5551 * @ctxt: the XPath Parser context
5552 * @cur: the current node in the traversal
5553 *
5554 * Traversal function for the "following-sibling" direction
5555 * The following-sibling axis contains the following siblings of the context
5556 * node in document order.
5557 *
5558 * Returns the next element following that axis
5559 */
5560xmlNodePtr
5561xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5562 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5563 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5564 return(NULL);
5565 if (cur == (xmlNodePtr) ctxt->context->doc)
5566 return(NULL);
5567 if (cur == NULL)
5568 return(ctxt->context->node->next);
5569 return(cur->next);
5570}
5571
5572/**
5573 * xmlXPathNextPrecedingSibling:
5574 * @ctxt: the XPath Parser context
5575 * @cur: the current node in the traversal
5576 *
5577 * Traversal function for the "preceding-sibling" direction
5578 * The preceding-sibling axis contains the preceding siblings of the context
5579 * node in reverse document order; the first preceding sibling is first on the
5580 * axis; the sibling preceding that node is the second on the axis and so on.
5581 *
5582 * Returns the next element following that axis
5583 */
5584xmlNodePtr
5585xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5586 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5587 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5588 return(NULL);
5589 if (cur == (xmlNodePtr) ctxt->context->doc)
5590 return(NULL);
5591 if (cur == NULL)
5592 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005593 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5594 cur = cur->prev;
5595 if (cur == NULL)
5596 return(ctxt->context->node->prev);
5597 }
Owen Taylor3473f882001-02-23 17:55:21 +00005598 return(cur->prev);
5599}
5600
5601/**
5602 * xmlXPathNextFollowing:
5603 * @ctxt: the XPath Parser context
5604 * @cur: the current node in the traversal
5605 *
5606 * Traversal function for the "following" direction
5607 * The following axis contains all nodes in the same document as the context
5608 * node that are after the context node in document order, excluding any
5609 * descendants and excluding attribute nodes and namespace nodes; the nodes
5610 * are ordered in document order
5611 *
5612 * Returns the next element following that axis
5613 */
5614xmlNodePtr
5615xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5616 if (cur != NULL && cur->children != NULL)
5617 return cur->children ;
5618 if (cur == NULL) cur = ctxt->context->node;
5619 if (cur == NULL) return(NULL) ; /* ERROR */
5620 if (cur->next != NULL) return(cur->next) ;
5621 do {
5622 cur = cur->parent;
5623 if (cur == NULL) return(NULL);
5624 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5625 if (cur->next != NULL) return(cur->next);
5626 } while (cur != NULL);
5627 return(cur);
5628}
5629
5630/*
5631 * xmlXPathIsAncestor:
5632 * @ancestor: the ancestor node
5633 * @node: the current node
5634 *
5635 * Check that @ancestor is a @node's ancestor
5636 *
5637 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5638 */
5639static int
5640xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5641 if ((ancestor == NULL) || (node == NULL)) return(0);
5642 /* nodes need to be in the same document */
5643 if (ancestor->doc != node->doc) return(0);
5644 /* avoid searching if ancestor or node is the root node */
5645 if (ancestor == (xmlNodePtr) node->doc) return(1);
5646 if (node == (xmlNodePtr) ancestor->doc) return(0);
5647 while (node->parent != NULL) {
5648 if (node->parent == ancestor)
5649 return(1);
5650 node = node->parent;
5651 }
5652 return(0);
5653}
5654
5655/**
5656 * xmlXPathNextPreceding:
5657 * @ctxt: the XPath Parser context
5658 * @cur: the current node in the traversal
5659 *
5660 * Traversal function for the "preceding" direction
5661 * the preceding axis contains all nodes in the same document as the context
5662 * node that are before the context node in document order, excluding any
5663 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5664 * ordered in reverse document order
5665 *
5666 * Returns the next element following that axis
5667 */
5668xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005669xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5670{
Owen Taylor3473f882001-02-23 17:55:21 +00005671 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005672 cur = ctxt->context->node;
5673 if (cur == NULL)
5674 return (NULL);
5675 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5676 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005677 do {
5678 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005679 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5680 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005681 }
5682
5683 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005684 if (cur == NULL)
5685 return (NULL);
5686 if (cur == ctxt->context->doc->children)
5687 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005688 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005689 return (cur);
5690}
5691
5692/**
5693 * xmlXPathNextPrecedingInternal:
5694 * @ctxt: the XPath Parser context
5695 * @cur: the current node in the traversal
5696 *
5697 * Traversal function for the "preceding" direction
5698 * the preceding axis contains all nodes in the same document as the context
5699 * node that are before the context node in document order, excluding any
5700 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5701 * ordered in reverse document order
5702 * This is a faster implementation but internal only since it requires a
5703 * state kept in the parser context: ctxt->ancestor.
5704 *
5705 * Returns the next element following that axis
5706 */
5707static xmlNodePtr
5708xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5709 xmlNodePtr cur)
5710{
5711 if (cur == NULL) {
5712 cur = ctxt->context->node;
5713 if (cur == NULL)
5714 return (NULL);
5715 ctxt->ancestor = cur->parent;
5716 }
5717 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5718 cur = cur->prev;
5719 while (cur->prev == NULL) {
5720 cur = cur->parent;
5721 if (cur == NULL)
5722 return (NULL);
5723 if (cur == ctxt->context->doc->children)
5724 return (NULL);
5725 if (cur != ctxt->ancestor)
5726 return (cur);
5727 ctxt->ancestor = cur->parent;
5728 }
5729 cur = cur->prev;
5730 while (cur->last != NULL)
5731 cur = cur->last;
5732 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005733}
5734
5735/**
5736 * xmlXPathNextNamespace:
5737 * @ctxt: the XPath Parser context
5738 * @cur: the current attribute in the traversal
5739 *
5740 * Traversal function for the "namespace" direction
5741 * the namespace axis contains the namespace nodes of the context node;
5742 * the order of nodes on this axis is implementation-defined; the axis will
5743 * be empty unless the context node is an element
5744 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005745 * We keep the XML namespace node at the end of the list.
5746 *
Owen Taylor3473f882001-02-23 17:55:21 +00005747 * Returns the next element following that axis
5748 */
5749xmlNodePtr
5750xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5751 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00005752 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005753 if (ctxt->context->tmpNsList != NULL)
5754 xmlFree(ctxt->context->tmpNsList);
5755 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005756 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005757 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005758 if (ctxt->context->tmpNsList != NULL) {
5759 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
5760 ctxt->context->tmpNsNr++;
5761 }
5762 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005763 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005764 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00005765 if (ctxt->context->tmpNsNr > 0) {
5766 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
5767 } else {
5768 if (ctxt->context->tmpNsList != NULL)
5769 xmlFree(ctxt->context->tmpNsList);
5770 ctxt->context->tmpNsList = NULL;
5771 return(NULL);
5772 }
Owen Taylor3473f882001-02-23 17:55:21 +00005773}
5774
5775/**
5776 * xmlXPathNextAttribute:
5777 * @ctxt: the XPath Parser context
5778 * @cur: the current attribute in the traversal
5779 *
5780 * Traversal function for the "attribute" direction
5781 * TODO: support DTD inherited default attributes
5782 *
5783 * Returns the next element following that axis
5784 */
5785xmlNodePtr
5786xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005787 if (ctxt->context->node == NULL)
5788 return(NULL);
5789 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5790 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005791 if (cur == NULL) {
5792 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5793 return(NULL);
5794 return((xmlNodePtr)ctxt->context->node->properties);
5795 }
5796 return((xmlNodePtr)cur->next);
5797}
5798
5799/************************************************************************
5800 * *
5801 * NodeTest Functions *
5802 * *
5803 ************************************************************************/
5804
Owen Taylor3473f882001-02-23 17:55:21 +00005805#define IS_FUNCTION 200
5806
Owen Taylor3473f882001-02-23 17:55:21 +00005807
5808/************************************************************************
5809 * *
5810 * Implicit tree core function library *
5811 * *
5812 ************************************************************************/
5813
5814/**
5815 * xmlXPathRoot:
5816 * @ctxt: the XPath Parser context
5817 *
5818 * Initialize the context to the root of the document
5819 */
5820void
5821xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5822 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5823 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5824}
5825
5826/************************************************************************
5827 * *
5828 * The explicit core function library *
5829 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5830 * *
5831 ************************************************************************/
5832
5833
5834/**
5835 * xmlXPathLastFunction:
5836 * @ctxt: the XPath Parser context
5837 * @nargs: the number of arguments
5838 *
5839 * Implement the last() XPath function
5840 * number last()
5841 * The last function returns the number of nodes in the context node list.
5842 */
5843void
5844xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5845 CHECK_ARITY(0);
5846 if (ctxt->context->contextSize >= 0) {
5847 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5848#ifdef DEBUG_EXPR
5849 xmlGenericError(xmlGenericErrorContext,
5850 "last() : %d\n", ctxt->context->contextSize);
5851#endif
5852 } else {
5853 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5854 }
5855}
5856
5857/**
5858 * xmlXPathPositionFunction:
5859 * @ctxt: the XPath Parser context
5860 * @nargs: the number of arguments
5861 *
5862 * Implement the position() XPath function
5863 * number position()
5864 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005865 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00005866 * will be equal to last().
5867 */
5868void
5869xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5870 CHECK_ARITY(0);
5871 if (ctxt->context->proximityPosition >= 0) {
5872 valuePush(ctxt,
5873 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5874#ifdef DEBUG_EXPR
5875 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5876 ctxt->context->proximityPosition);
5877#endif
5878 } else {
5879 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5880 }
5881}
5882
5883/**
5884 * xmlXPathCountFunction:
5885 * @ctxt: the XPath Parser context
5886 * @nargs: the number of arguments
5887 *
5888 * Implement the count() XPath function
5889 * number count(node-set)
5890 */
5891void
5892xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5893 xmlXPathObjectPtr cur;
5894
5895 CHECK_ARITY(1);
5896 if ((ctxt->value == NULL) ||
5897 ((ctxt->value->type != XPATH_NODESET) &&
5898 (ctxt->value->type != XPATH_XSLT_TREE)))
5899 XP_ERROR(XPATH_INVALID_TYPE);
5900 cur = valuePop(ctxt);
5901
Daniel Veillard911f49a2001-04-07 15:39:35 +00005902 if ((cur == NULL) || (cur->nodesetval == NULL))
5903 valuePush(ctxt, xmlXPathNewFloat((double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00005904 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00005905 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00005906 } else {
5907 if ((cur->nodesetval->nodeNr != 1) ||
5908 (cur->nodesetval->nodeTab == NULL)) {
5909 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5910 } else {
5911 xmlNodePtr tmp;
5912 int i = 0;
5913
5914 tmp = cur->nodesetval->nodeTab[0];
5915 if (tmp != NULL) {
5916 tmp = tmp->children;
5917 while (tmp != NULL) {
5918 tmp = tmp->next;
5919 i++;
5920 }
5921 }
5922 valuePush(ctxt, xmlXPathNewFloat((double) i));
5923 }
5924 }
Owen Taylor3473f882001-02-23 17:55:21 +00005925 xmlXPathFreeObject(cur);
5926}
5927
5928/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005929 * xmlXPathGetElementsByIds:
5930 * @doc: the document
5931 * @ids: a whitespace separated list of IDs
5932 *
5933 * Selects elements by their unique ID.
5934 *
5935 * Returns a node-set of selected elements.
5936 */
5937static xmlNodeSetPtr
5938xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5939 xmlNodeSetPtr ret;
5940 const xmlChar *cur = ids;
5941 xmlChar *ID;
5942 xmlAttrPtr attr;
5943 xmlNodePtr elem = NULL;
5944
5945 ret = xmlXPathNodeSetCreate(NULL);
5946
5947 while (IS_BLANK(*cur)) cur++;
5948 while (*cur != 0) {
Daniel Veillarde209b332003-03-26 21:40:13 +00005949 while ((!IS_BLANK(*cur)) && (*cur != 0))
5950 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005951
5952 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00005953 if (ID != NULL) {
5954 if (xmlValidateNCName(ID, 1) == 0) {
5955 attr = xmlGetID(doc, ID);
5956 if (attr != NULL) {
5957 if (attr->type == XML_ATTRIBUTE_NODE)
5958 elem = attr->parent;
5959 else if (attr->type == XML_ELEMENT_NODE)
5960 elem = (xmlNodePtr) attr;
5961 else
5962 elem = NULL;
5963 if (elem != NULL)
5964 xmlXPathNodeSetAdd(ret, elem);
5965 }
5966 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005967 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00005968 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005969
5970 while (IS_BLANK(*cur)) cur++;
5971 ids = cur;
5972 }
5973 return(ret);
5974}
5975
5976/**
Owen Taylor3473f882001-02-23 17:55:21 +00005977 * xmlXPathIdFunction:
5978 * @ctxt: the XPath Parser context
5979 * @nargs: the number of arguments
5980 *
5981 * Implement the id() XPath function
5982 * node-set id(object)
5983 * The id function selects elements by their unique ID
5984 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
5985 * then the result is the union of the result of applying id to the
5986 * string value of each of the nodes in the argument node-set. When the
5987 * argument to id is of any other type, the argument is converted to a
5988 * string as if by a call to the string function; the string is split
5989 * into a whitespace-separated list of tokens (whitespace is any sequence
5990 * of characters matching the production S); the result is a node-set
5991 * containing the elements in the same document as the context node that
5992 * have a unique ID equal to any of the tokens in the list.
5993 */
5994void
5995xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005996 xmlChar *tokens;
5997 xmlNodeSetPtr ret;
5998 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00005999
6000 CHECK_ARITY(1);
6001 obj = valuePop(ctxt);
6002 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00006003 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006004 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00006005 int i;
6006
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006007 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006008
Daniel Veillard911f49a2001-04-07 15:39:35 +00006009 if (obj->nodesetval != NULL) {
6010 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006011 tokens =
6012 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
6013 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
6014 ret = xmlXPathNodeSetMerge(ret, ns);
6015 xmlXPathFreeNodeSet(ns);
6016 if (tokens != NULL)
6017 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006018 }
Owen Taylor3473f882001-02-23 17:55:21 +00006019 }
6020
6021 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006022 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006023 return;
6024 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006025 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00006026
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006027 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
6028 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006029
Owen Taylor3473f882001-02-23 17:55:21 +00006030 xmlXPathFreeObject(obj);
6031 return;
6032}
6033
6034/**
6035 * xmlXPathLocalNameFunction:
6036 * @ctxt: the XPath Parser context
6037 * @nargs: the number of arguments
6038 *
6039 * Implement the local-name() XPath function
6040 * string local-name(node-set?)
6041 * The local-name function returns a string containing the local part
6042 * of the name of the node in the argument node-set that is first in
6043 * document order. If the node-set is empty or the first node has no
6044 * name, an empty string is returned. If the argument is omitted it
6045 * defaults to the context node.
6046 */
6047void
6048xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6049 xmlXPathObjectPtr cur;
6050
6051 if (nargs == 0) {
6052 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6053 nargs = 1;
6054 }
6055
6056 CHECK_ARITY(1);
6057 if ((ctxt->value == NULL) ||
6058 ((ctxt->value->type != XPATH_NODESET) &&
6059 (ctxt->value->type != XPATH_XSLT_TREE)))
6060 XP_ERROR(XPATH_INVALID_TYPE);
6061 cur = valuePop(ctxt);
6062
Daniel Veillard911f49a2001-04-07 15:39:35 +00006063 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006064 valuePush(ctxt, xmlXPathNewCString(""));
6065 } else {
6066 int i = 0; /* Should be first in document order !!!!! */
6067 switch (cur->nodesetval->nodeTab[i]->type) {
6068 case XML_ELEMENT_NODE:
6069 case XML_ATTRIBUTE_NODE:
6070 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006071 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6072 valuePush(ctxt, xmlXPathNewCString(""));
6073 else
6074 valuePush(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006075 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
6076 break;
6077 case XML_NAMESPACE_DECL:
6078 valuePush(ctxt, xmlXPathNewString(
6079 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
6080 break;
6081 default:
6082 valuePush(ctxt, xmlXPathNewCString(""));
6083 }
6084 }
6085 xmlXPathFreeObject(cur);
6086}
6087
6088/**
6089 * xmlXPathNamespaceURIFunction:
6090 * @ctxt: the XPath Parser context
6091 * @nargs: the number of arguments
6092 *
6093 * Implement the namespace-uri() XPath function
6094 * string namespace-uri(node-set?)
6095 * The namespace-uri function returns a string containing the
6096 * namespace URI of the expanded name of the node in the argument
6097 * node-set that is first in document order. If the node-set is empty,
6098 * the first node has no name, or the expanded name has no namespace
6099 * URI, an empty string is returned. If the argument is omitted it
6100 * defaults to the context node.
6101 */
6102void
6103xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6104 xmlXPathObjectPtr cur;
6105
6106 if (nargs == 0) {
6107 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6108 nargs = 1;
6109 }
6110 CHECK_ARITY(1);
6111 if ((ctxt->value == NULL) ||
6112 ((ctxt->value->type != XPATH_NODESET) &&
6113 (ctxt->value->type != XPATH_XSLT_TREE)))
6114 XP_ERROR(XPATH_INVALID_TYPE);
6115 cur = valuePop(ctxt);
6116
Daniel Veillard911f49a2001-04-07 15:39:35 +00006117 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006118 valuePush(ctxt, xmlXPathNewCString(""));
6119 } else {
6120 int i = 0; /* Should be first in document order !!!!! */
6121 switch (cur->nodesetval->nodeTab[i]->type) {
6122 case XML_ELEMENT_NODE:
6123 case XML_ATTRIBUTE_NODE:
6124 if (cur->nodesetval->nodeTab[i]->ns == NULL)
6125 valuePush(ctxt, xmlXPathNewCString(""));
6126 else
6127 valuePush(ctxt, xmlXPathNewString(
6128 cur->nodesetval->nodeTab[i]->ns->href));
6129 break;
6130 default:
6131 valuePush(ctxt, xmlXPathNewCString(""));
6132 }
6133 }
6134 xmlXPathFreeObject(cur);
6135}
6136
6137/**
6138 * xmlXPathNameFunction:
6139 * @ctxt: the XPath Parser context
6140 * @nargs: the number of arguments
6141 *
6142 * Implement the name() XPath function
6143 * string name(node-set?)
6144 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006145 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00006146 * order. The QName must represent the name with respect to the namespace
6147 * declarations in effect on the node whose name is being represented.
6148 * Typically, this will be the form in which the name occurred in the XML
6149 * source. This need not be the case if there are namespace declarations
6150 * in effect on the node that associate multiple prefixes with the same
6151 * namespace. However, an implementation may include information about
6152 * the original prefix in its representation of nodes; in this case, an
6153 * implementation can ensure that the returned string is always the same
6154 * as the QName used in the XML source. If the argument it omitted it
6155 * defaults to the context node.
6156 * Libxml keep the original prefix so the "real qualified name" used is
6157 * returned.
6158 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006159static void
Daniel Veillard04383752001-07-08 14:27:15 +00006160xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
6161{
Owen Taylor3473f882001-02-23 17:55:21 +00006162 xmlXPathObjectPtr cur;
6163
6164 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00006165 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6166 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006167 }
6168
6169 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00006170 if ((ctxt->value == NULL) ||
6171 ((ctxt->value->type != XPATH_NODESET) &&
6172 (ctxt->value->type != XPATH_XSLT_TREE)))
6173 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006174 cur = valuePop(ctxt);
6175
Daniel Veillard911f49a2001-04-07 15:39:35 +00006176 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006177 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00006178 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006179 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00006180
Daniel Veillard04383752001-07-08 14:27:15 +00006181 switch (cur->nodesetval->nodeTab[i]->type) {
6182 case XML_ELEMENT_NODE:
6183 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006184 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6185 valuePush(ctxt, xmlXPathNewCString(""));
6186 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6187 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006188 valuePush(ctxt,
6189 xmlXPathNewString(cur->nodesetval->
6190 nodeTab[i]->name));
6191
Daniel Veillard652d8a92003-02-04 19:28:49 +00006192 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006193 char name[2000];
6194
6195 snprintf(name, sizeof(name), "%s:%s",
6196 (char *) cur->nodesetval->nodeTab[i]->ns->
6197 prefix,
6198 (char *) cur->nodesetval->nodeTab[i]->name);
6199 name[sizeof(name) - 1] = 0;
6200 valuePush(ctxt, xmlXPathNewCString(name));
6201 }
6202 break;
6203 default:
6204 valuePush(ctxt,
6205 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6206 xmlXPathLocalNameFunction(ctxt, 1);
6207 }
Owen Taylor3473f882001-02-23 17:55:21 +00006208 }
6209 xmlXPathFreeObject(cur);
6210}
6211
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006212
6213/**
Owen Taylor3473f882001-02-23 17:55:21 +00006214 * xmlXPathStringFunction:
6215 * @ctxt: the XPath Parser context
6216 * @nargs: the number of arguments
6217 *
6218 * Implement the string() XPath function
6219 * string string(object?)
6220 * he string function converts an object to a string as follows:
6221 * - A node-set is converted to a string by returning the value of
6222 * the node in the node-set that is first in document order.
6223 * If the node-set is empty, an empty string is returned.
6224 * - A number is converted to a string as follows
6225 * + NaN is converted to the string NaN
6226 * + positive zero is converted to the string 0
6227 * + negative zero is converted to the string 0
6228 * + positive infinity is converted to the string Infinity
6229 * + negative infinity is converted to the string -Infinity
6230 * + if the number is an integer, the number is represented in
6231 * decimal form as a Number with no decimal point and no leading
6232 * zeros, preceded by a minus sign (-) if the number is negative
6233 * + otherwise, the number is represented in decimal form as a
6234 * Number including a decimal point with at least one digit
6235 * before the decimal point and at least one digit after the
6236 * decimal point, preceded by a minus sign (-) if the number
6237 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006238 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00006239 * before the decimal point; beyond the one required digit
6240 * after the decimal point there must be as many, but only as
6241 * many, more digits as are needed to uniquely distinguish the
6242 * number from all other IEEE 754 numeric values.
6243 * - The boolean false value is converted to the string false.
6244 * The boolean true value is converted to the string true.
6245 *
6246 * If the argument is omitted, it defaults to a node-set with the
6247 * context node as its only member.
6248 */
6249void
6250xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6251 xmlXPathObjectPtr cur;
6252
6253 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006254 valuePush(ctxt,
6255 xmlXPathWrapString(
6256 xmlXPathCastNodeToString(ctxt->context->node)));
6257 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006258 }
6259
6260 CHECK_ARITY(1);
6261 cur = valuePop(ctxt);
6262 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006263 cur = xmlXPathConvertString(cur);
6264 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006265}
6266
6267/**
6268 * xmlXPathStringLengthFunction:
6269 * @ctxt: the XPath Parser context
6270 * @nargs: the number of arguments
6271 *
6272 * Implement the string-length() XPath function
6273 * number string-length(string?)
6274 * The string-length returns the number of characters in the string
6275 * (see [3.6 Strings]). If the argument is omitted, it defaults to
6276 * the context node converted to a string, in other words the value
6277 * of the context node.
6278 */
6279void
6280xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6281 xmlXPathObjectPtr cur;
6282
6283 if (nargs == 0) {
6284 if (ctxt->context->node == NULL) {
6285 valuePush(ctxt, xmlXPathNewFloat(0));
6286 } else {
6287 xmlChar *content;
6288
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006289 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006290 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00006291 xmlFree(content);
6292 }
6293 return;
6294 }
6295 CHECK_ARITY(1);
6296 CAST_TO_STRING;
6297 CHECK_TYPE(XPATH_STRING);
6298 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006299 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00006300 xmlXPathFreeObject(cur);
6301}
6302
6303/**
6304 * xmlXPathConcatFunction:
6305 * @ctxt: the XPath Parser context
6306 * @nargs: the number of arguments
6307 *
6308 * Implement the concat() XPath function
6309 * string concat(string, string, string*)
6310 * The concat function returns the concatenation of its arguments.
6311 */
6312void
6313xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6314 xmlXPathObjectPtr cur, newobj;
6315 xmlChar *tmp;
6316
6317 if (nargs < 2) {
6318 CHECK_ARITY(2);
6319 }
6320
6321 CAST_TO_STRING;
6322 cur = valuePop(ctxt);
6323 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6324 xmlXPathFreeObject(cur);
6325 return;
6326 }
6327 nargs--;
6328
6329 while (nargs > 0) {
6330 CAST_TO_STRING;
6331 newobj = valuePop(ctxt);
6332 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6333 xmlXPathFreeObject(newobj);
6334 xmlXPathFreeObject(cur);
6335 XP_ERROR(XPATH_INVALID_TYPE);
6336 }
6337 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6338 newobj->stringval = cur->stringval;
6339 cur->stringval = tmp;
6340
6341 xmlXPathFreeObject(newobj);
6342 nargs--;
6343 }
6344 valuePush(ctxt, cur);
6345}
6346
6347/**
6348 * xmlXPathContainsFunction:
6349 * @ctxt: the XPath Parser context
6350 * @nargs: the number of arguments
6351 *
6352 * Implement the contains() XPath function
6353 * boolean contains(string, string)
6354 * The contains function returns true if the first argument string
6355 * contains the second argument string, and otherwise returns false.
6356 */
6357void
6358xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6359 xmlXPathObjectPtr hay, needle;
6360
6361 CHECK_ARITY(2);
6362 CAST_TO_STRING;
6363 CHECK_TYPE(XPATH_STRING);
6364 needle = valuePop(ctxt);
6365 CAST_TO_STRING;
6366 hay = valuePop(ctxt);
6367 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6368 xmlXPathFreeObject(hay);
6369 xmlXPathFreeObject(needle);
6370 XP_ERROR(XPATH_INVALID_TYPE);
6371 }
6372 if (xmlStrstr(hay->stringval, needle->stringval))
6373 valuePush(ctxt, xmlXPathNewBoolean(1));
6374 else
6375 valuePush(ctxt, xmlXPathNewBoolean(0));
6376 xmlXPathFreeObject(hay);
6377 xmlXPathFreeObject(needle);
6378}
6379
6380/**
6381 * xmlXPathStartsWithFunction:
6382 * @ctxt: the XPath Parser context
6383 * @nargs: the number of arguments
6384 *
6385 * Implement the starts-with() XPath function
6386 * boolean starts-with(string, string)
6387 * The starts-with function returns true if the first argument string
6388 * starts with the second argument string, and otherwise returns false.
6389 */
6390void
6391xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6392 xmlXPathObjectPtr hay, needle;
6393 int n;
6394
6395 CHECK_ARITY(2);
6396 CAST_TO_STRING;
6397 CHECK_TYPE(XPATH_STRING);
6398 needle = valuePop(ctxt);
6399 CAST_TO_STRING;
6400 hay = valuePop(ctxt);
6401 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6402 xmlXPathFreeObject(hay);
6403 xmlXPathFreeObject(needle);
6404 XP_ERROR(XPATH_INVALID_TYPE);
6405 }
6406 n = xmlStrlen(needle->stringval);
6407 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6408 valuePush(ctxt, xmlXPathNewBoolean(0));
6409 else
6410 valuePush(ctxt, xmlXPathNewBoolean(1));
6411 xmlXPathFreeObject(hay);
6412 xmlXPathFreeObject(needle);
6413}
6414
6415/**
6416 * xmlXPathSubstringFunction:
6417 * @ctxt: the XPath Parser context
6418 * @nargs: the number of arguments
6419 *
6420 * Implement the substring() XPath function
6421 * string substring(string, number, number?)
6422 * The substring function returns the substring of the first argument
6423 * starting at the position specified in the second argument with
6424 * length specified in the third argument. For example,
6425 * substring("12345",2,3) returns "234". If the third argument is not
6426 * specified, it returns the substring starting at the position specified
6427 * in the second argument and continuing to the end of the string. For
6428 * example, substring("12345",2) returns "2345". More precisely, each
6429 * character in the string (see [3.6 Strings]) is considered to have a
6430 * numeric position: the position of the first character is 1, the position
6431 * of the second character is 2 and so on. The returned substring contains
6432 * those characters for which the position of the character is greater than
6433 * or equal to the second argument and, if the third argument is specified,
6434 * less than the sum of the second and third arguments; the comparisons
6435 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6436 * - substring("12345", 1.5, 2.6) returns "234"
6437 * - substring("12345", 0, 3) returns "12"
6438 * - substring("12345", 0 div 0, 3) returns ""
6439 * - substring("12345", 1, 0 div 0) returns ""
6440 * - substring("12345", -42, 1 div 0) returns "12345"
6441 * - substring("12345", -1 div 0, 1 div 0) returns ""
6442 */
6443void
6444xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6445 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006446 double le=0, in;
6447 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006448 xmlChar *ret;
6449
Owen Taylor3473f882001-02-23 17:55:21 +00006450 if (nargs < 2) {
6451 CHECK_ARITY(2);
6452 }
6453 if (nargs > 3) {
6454 CHECK_ARITY(3);
6455 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006456 /*
6457 * take care of possible last (position) argument
6458 */
Owen Taylor3473f882001-02-23 17:55:21 +00006459 if (nargs == 3) {
6460 CAST_TO_NUMBER;
6461 CHECK_TYPE(XPATH_NUMBER);
6462 len = valuePop(ctxt);
6463 le = len->floatval;
6464 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006465 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006466
Owen Taylor3473f882001-02-23 17:55:21 +00006467 CAST_TO_NUMBER;
6468 CHECK_TYPE(XPATH_NUMBER);
6469 start = valuePop(ctxt);
6470 in = start->floatval;
6471 xmlXPathFreeObject(start);
6472 CAST_TO_STRING;
6473 CHECK_TYPE(XPATH_STRING);
6474 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006475 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006476
Daniel Veillard97ac1312001-05-30 19:14:17 +00006477 /*
6478 * If last pos not present, calculate last position
6479 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006480 if (nargs != 3) {
6481 le = (double)m;
6482 if (in < 1.0)
6483 in = 1.0;
6484 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006485
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006486 /* Need to check for the special cases where either
6487 * the index is NaN, the length is NaN, or both
6488 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00006489 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006490 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006491 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00006492 * To meet the requirements of the spec, the arguments
6493 * must be converted to integer format before
6494 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006495 *
Daniel Veillard9e412302002-06-10 15:59:44 +00006496 * First we go to integer form, rounding up
6497 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006498 */
6499 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00006500 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00006501
Daniel Veillard9e412302002-06-10 15:59:44 +00006502 if (xmlXPathIsInf(le) == 1) {
6503 l = m;
6504 if (i < 1)
6505 i = 1;
6506 }
6507 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
6508 l = 0;
6509 else {
6510 l = (int) le;
6511 if (((double)l)+0.5 <= le) l++;
6512 }
6513
6514 /* Now we normalize inidices */
6515 i -= 1;
6516 l += i;
6517 if (i < 0)
6518 i = 0;
6519 if (l > m)
6520 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00006521
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006522 /* number of chars to copy */
6523 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00006524
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006525 ret = xmlUTF8Strsub(str->stringval, i, l);
6526 }
6527 else {
6528 ret = NULL;
6529 }
6530
Owen Taylor3473f882001-02-23 17:55:21 +00006531 if (ret == NULL)
6532 valuePush(ctxt, xmlXPathNewCString(""));
6533 else {
6534 valuePush(ctxt, xmlXPathNewString(ret));
6535 xmlFree(ret);
6536 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006537
Owen Taylor3473f882001-02-23 17:55:21 +00006538 xmlXPathFreeObject(str);
6539}
6540
6541/**
6542 * xmlXPathSubstringBeforeFunction:
6543 * @ctxt: the XPath Parser context
6544 * @nargs: the number of arguments
6545 *
6546 * Implement the substring-before() XPath function
6547 * string substring-before(string, string)
6548 * The substring-before function returns the substring of the first
6549 * argument string that precedes the first occurrence of the second
6550 * argument string in the first argument string, or the empty string
6551 * if the first argument string does not contain the second argument
6552 * string. For example, substring-before("1999/04/01","/") returns 1999.
6553 */
6554void
6555xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6556 xmlXPathObjectPtr str;
6557 xmlXPathObjectPtr find;
6558 xmlBufferPtr target;
6559 const xmlChar *point;
6560 int offset;
6561
6562 CHECK_ARITY(2);
6563 CAST_TO_STRING;
6564 find = valuePop(ctxt);
6565 CAST_TO_STRING;
6566 str = valuePop(ctxt);
6567
6568 target = xmlBufferCreate();
6569 if (target) {
6570 point = xmlStrstr(str->stringval, find->stringval);
6571 if (point) {
6572 offset = (int)(point - str->stringval);
6573 xmlBufferAdd(target, str->stringval, offset);
6574 }
6575 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6576 xmlBufferFree(target);
6577 }
6578
6579 xmlXPathFreeObject(str);
6580 xmlXPathFreeObject(find);
6581}
6582
6583/**
6584 * xmlXPathSubstringAfterFunction:
6585 * @ctxt: the XPath Parser context
6586 * @nargs: the number of arguments
6587 *
6588 * Implement the substring-after() XPath function
6589 * string substring-after(string, string)
6590 * The substring-after function returns the substring of the first
6591 * argument string that follows the first occurrence of the second
6592 * argument string in the first argument string, or the empty stringi
6593 * if the first argument string does not contain the second argument
6594 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6595 * and substring-after("1999/04/01","19") returns 99/04/01.
6596 */
6597void
6598xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6599 xmlXPathObjectPtr str;
6600 xmlXPathObjectPtr find;
6601 xmlBufferPtr target;
6602 const xmlChar *point;
6603 int offset;
6604
6605 CHECK_ARITY(2);
6606 CAST_TO_STRING;
6607 find = valuePop(ctxt);
6608 CAST_TO_STRING;
6609 str = valuePop(ctxt);
6610
6611 target = xmlBufferCreate();
6612 if (target) {
6613 point = xmlStrstr(str->stringval, find->stringval);
6614 if (point) {
6615 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6616 xmlBufferAdd(target, &str->stringval[offset],
6617 xmlStrlen(str->stringval) - offset);
6618 }
6619 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6620 xmlBufferFree(target);
6621 }
6622
6623 xmlXPathFreeObject(str);
6624 xmlXPathFreeObject(find);
6625}
6626
6627/**
6628 * xmlXPathNormalizeFunction:
6629 * @ctxt: the XPath Parser context
6630 * @nargs: the number of arguments
6631 *
6632 * Implement the normalize-space() XPath function
6633 * string normalize-space(string?)
6634 * The normalize-space function returns the argument string with white
6635 * space normalized by stripping leading and trailing whitespace
6636 * and replacing sequences of whitespace characters by a single
6637 * space. Whitespace characters are the same allowed by the S production
6638 * in XML. If the argument is omitted, it defaults to the context
6639 * node converted to a string, in other words the value of the context node.
6640 */
6641void
6642xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6643 xmlXPathObjectPtr obj = NULL;
6644 xmlChar *source = NULL;
6645 xmlBufferPtr target;
6646 xmlChar blank;
6647
6648 if (nargs == 0) {
6649 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006650 valuePush(ctxt,
6651 xmlXPathWrapString(
6652 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006653 nargs = 1;
6654 }
6655
6656 CHECK_ARITY(1);
6657 CAST_TO_STRING;
6658 CHECK_TYPE(XPATH_STRING);
6659 obj = valuePop(ctxt);
6660 source = obj->stringval;
6661
6662 target = xmlBufferCreate();
6663 if (target && source) {
6664
6665 /* Skip leading whitespaces */
6666 while (IS_BLANK(*source))
6667 source++;
6668
6669 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6670 blank = 0;
6671 while (*source) {
6672 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006673 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006674 } else {
6675 if (blank) {
6676 xmlBufferAdd(target, &blank, 1);
6677 blank = 0;
6678 }
6679 xmlBufferAdd(target, source, 1);
6680 }
6681 source++;
6682 }
6683
6684 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6685 xmlBufferFree(target);
6686 }
6687 xmlXPathFreeObject(obj);
6688}
6689
6690/**
6691 * xmlXPathTranslateFunction:
6692 * @ctxt: the XPath Parser context
6693 * @nargs: the number of arguments
6694 *
6695 * Implement the translate() XPath function
6696 * string translate(string, string, string)
6697 * The translate function returns the first argument string with
6698 * occurrences of characters in the second argument string replaced
6699 * by the character at the corresponding position in the third argument
6700 * string. For example, translate("bar","abc","ABC") returns the string
6701 * BAr. If there is a character in the second argument string with no
6702 * character at a corresponding position in the third argument string
6703 * (because the second argument string is longer than the third argument
6704 * string), then occurrences of that character in the first argument
6705 * string are removed. For example, translate("--aaa--","abc-","ABC")
6706 * returns "AAA". If a character occurs more than once in second
6707 * argument string, then the first occurrence determines the replacement
6708 * character. If the third argument string is longer than the second
6709 * argument string, then excess characters are ignored.
6710 */
6711void
6712xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006713 xmlXPathObjectPtr str;
6714 xmlXPathObjectPtr from;
6715 xmlXPathObjectPtr to;
6716 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006717 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006718 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006719 xmlChar *point;
6720 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006721
Daniel Veillarde043ee12001-04-16 14:08:07 +00006722 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006723
Daniel Veillarde043ee12001-04-16 14:08:07 +00006724 CAST_TO_STRING;
6725 to = valuePop(ctxt);
6726 CAST_TO_STRING;
6727 from = valuePop(ctxt);
6728 CAST_TO_STRING;
6729 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006730
Daniel Veillarde043ee12001-04-16 14:08:07 +00006731 target = xmlBufferCreate();
6732 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006733 max = xmlUTF8Strlen(to->stringval);
6734 for (cptr = str->stringval; (ch=*cptr); ) {
6735 offset = xmlUTF8Strloc(from->stringval, cptr);
6736 if (offset >= 0) {
6737 if (offset < max) {
6738 point = xmlUTF8Strpos(to->stringval, offset);
6739 if (point)
6740 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6741 }
6742 } else
6743 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6744
6745 /* Step to next character in input */
6746 cptr++;
6747 if ( ch & 0x80 ) {
6748 /* if not simple ascii, verify proper format */
6749 if ( (ch & 0xc0) != 0xc0 ) {
6750 xmlGenericError(xmlGenericErrorContext,
6751 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6752 break;
6753 }
6754 /* then skip over remaining bytes for this char */
6755 while ( (ch <<= 1) & 0x80 )
6756 if ( (*cptr++ & 0xc0) != 0x80 ) {
6757 xmlGenericError(xmlGenericErrorContext,
6758 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6759 break;
6760 }
6761 if (ch & 0x80) /* must have had error encountered */
6762 break;
6763 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006764 }
Owen Taylor3473f882001-02-23 17:55:21 +00006765 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006766 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6767 xmlBufferFree(target);
6768 xmlXPathFreeObject(str);
6769 xmlXPathFreeObject(from);
6770 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006771}
6772
6773/**
6774 * xmlXPathBooleanFunction:
6775 * @ctxt: the XPath Parser context
6776 * @nargs: the number of arguments
6777 *
6778 * Implement the boolean() XPath function
6779 * boolean boolean(object)
6780 * he boolean function converts its argument to a boolean as follows:
6781 * - a number is true if and only if it is neither positive or
6782 * negative zero nor NaN
6783 * - a node-set is true if and only if it is non-empty
6784 * - a string is true if and only if its length is non-zero
6785 */
6786void
6787xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6788 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006789
6790 CHECK_ARITY(1);
6791 cur = valuePop(ctxt);
6792 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006793 cur = xmlXPathConvertBoolean(cur);
6794 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006795}
6796
6797/**
6798 * xmlXPathNotFunction:
6799 * @ctxt: the XPath Parser context
6800 * @nargs: the number of arguments
6801 *
6802 * Implement the not() XPath function
6803 * boolean not(boolean)
6804 * The not function returns true if its argument is false,
6805 * and false otherwise.
6806 */
6807void
6808xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6809 CHECK_ARITY(1);
6810 CAST_TO_BOOLEAN;
6811 CHECK_TYPE(XPATH_BOOLEAN);
6812 ctxt->value->boolval = ! ctxt->value->boolval;
6813}
6814
6815/**
6816 * xmlXPathTrueFunction:
6817 * @ctxt: the XPath Parser context
6818 * @nargs: the number of arguments
6819 *
6820 * Implement the true() XPath function
6821 * boolean true()
6822 */
6823void
6824xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6825 CHECK_ARITY(0);
6826 valuePush(ctxt, xmlXPathNewBoolean(1));
6827}
6828
6829/**
6830 * xmlXPathFalseFunction:
6831 * @ctxt: the XPath Parser context
6832 * @nargs: the number of arguments
6833 *
6834 * Implement the false() XPath function
6835 * boolean false()
6836 */
6837void
6838xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6839 CHECK_ARITY(0);
6840 valuePush(ctxt, xmlXPathNewBoolean(0));
6841}
6842
6843/**
6844 * xmlXPathLangFunction:
6845 * @ctxt: the XPath Parser context
6846 * @nargs: the number of arguments
6847 *
6848 * Implement the lang() XPath function
6849 * boolean lang(string)
6850 * The lang function returns true or false depending on whether the
6851 * language of the context node as specified by xml:lang attributes
6852 * is the same as or is a sublanguage of the language specified by
6853 * the argument string. The language of the context node is determined
6854 * by the value of the xml:lang attribute on the context node, or, if
6855 * the context node has no xml:lang attribute, by the value of the
6856 * xml:lang attribute on the nearest ancestor of the context node that
6857 * has an xml:lang attribute. If there is no such attribute, then lang
6858 * returns false. If there is such an attribute, then lang returns
6859 * true if the attribute value is equal to the argument ignoring case,
6860 * or if there is some suffix starting with - such that the attribute
6861 * value is equal to the argument ignoring that suffix of the attribute
6862 * value and ignoring case.
6863 */
6864void
6865xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6866 xmlXPathObjectPtr val;
6867 const xmlChar *theLang;
6868 const xmlChar *lang;
6869 int ret = 0;
6870 int i;
6871
6872 CHECK_ARITY(1);
6873 CAST_TO_STRING;
6874 CHECK_TYPE(XPATH_STRING);
6875 val = valuePop(ctxt);
6876 lang = val->stringval;
6877 theLang = xmlNodeGetLang(ctxt->context->node);
6878 if ((theLang != NULL) && (lang != NULL)) {
6879 for (i = 0;lang[i] != 0;i++)
6880 if (toupper(lang[i]) != toupper(theLang[i]))
6881 goto not_equal;
6882 ret = 1;
6883 }
6884not_equal:
6885 xmlXPathFreeObject(val);
6886 valuePush(ctxt, xmlXPathNewBoolean(ret));
6887}
6888
6889/**
6890 * xmlXPathNumberFunction:
6891 * @ctxt: the XPath Parser context
6892 * @nargs: the number of arguments
6893 *
6894 * Implement the number() XPath function
6895 * number number(object?)
6896 */
6897void
6898xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6899 xmlXPathObjectPtr cur;
6900 double res;
6901
6902 if (nargs == 0) {
6903 if (ctxt->context->node == NULL) {
6904 valuePush(ctxt, xmlXPathNewFloat(0.0));
6905 } else {
6906 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6907
6908 res = xmlXPathStringEvalNumber(content);
6909 valuePush(ctxt, xmlXPathNewFloat(res));
6910 xmlFree(content);
6911 }
6912 return;
6913 }
6914
6915 CHECK_ARITY(1);
6916 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006917 cur = xmlXPathConvertNumber(cur);
6918 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006919}
6920
6921/**
6922 * xmlXPathSumFunction:
6923 * @ctxt: the XPath Parser context
6924 * @nargs: the number of arguments
6925 *
6926 * Implement the sum() XPath function
6927 * number sum(node-set)
6928 * The sum function returns the sum of the values of the nodes in
6929 * the argument node-set.
6930 */
6931void
6932xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6933 xmlXPathObjectPtr cur;
6934 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006935 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00006936
6937 CHECK_ARITY(1);
6938 if ((ctxt->value == NULL) ||
6939 ((ctxt->value->type != XPATH_NODESET) &&
6940 (ctxt->value->type != XPATH_XSLT_TREE)))
6941 XP_ERROR(XPATH_INVALID_TYPE);
6942 cur = valuePop(ctxt);
6943
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006944 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006945 valuePush(ctxt, xmlXPathNewFloat(0.0));
6946 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006947 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
6948 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006949 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006950 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00006951 }
6952 xmlXPathFreeObject(cur);
6953}
6954
6955/**
6956 * xmlXPathFloorFunction:
6957 * @ctxt: the XPath Parser context
6958 * @nargs: the number of arguments
6959 *
6960 * Implement the floor() XPath function
6961 * number floor(number)
6962 * The floor function returns the largest (closest to positive infinity)
6963 * number that is not greater than the argument and that is an integer.
6964 */
6965void
6966xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006967 double f;
6968
Owen Taylor3473f882001-02-23 17:55:21 +00006969 CHECK_ARITY(1);
6970 CAST_TO_NUMBER;
6971 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006972
6973 f = (double)((int) ctxt->value->floatval);
6974 if (f != ctxt->value->floatval) {
6975 if (ctxt->value->floatval > 0)
6976 ctxt->value->floatval = f;
6977 else
6978 ctxt->value->floatval = f - 1;
6979 }
Owen Taylor3473f882001-02-23 17:55:21 +00006980}
6981
6982/**
6983 * xmlXPathCeilingFunction:
6984 * @ctxt: the XPath Parser context
6985 * @nargs: the number of arguments
6986 *
6987 * Implement the ceiling() XPath function
6988 * number ceiling(number)
6989 * The ceiling function returns the smallest (closest to negative infinity)
6990 * number that is not less than the argument and that is an integer.
6991 */
6992void
6993xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6994 double f;
6995
6996 CHECK_ARITY(1);
6997 CAST_TO_NUMBER;
6998 CHECK_TYPE(XPATH_NUMBER);
6999
7000#if 0
7001 ctxt->value->floatval = ceil(ctxt->value->floatval);
7002#else
7003 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007004 if (f != ctxt->value->floatval) {
7005 if (ctxt->value->floatval > 0)
7006 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007007 else {
7008 if (ctxt->value->floatval < 0 && f == 0)
7009 ctxt->value->floatval = xmlXPathNZERO;
7010 else
7011 ctxt->value->floatval = f;
7012 }
7013
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007014 }
Owen Taylor3473f882001-02-23 17:55:21 +00007015#endif
7016}
7017
7018/**
7019 * xmlXPathRoundFunction:
7020 * @ctxt: the XPath Parser context
7021 * @nargs: the number of arguments
7022 *
7023 * Implement the round() XPath function
7024 * number round(number)
7025 * The round function returns the number that is closest to the
7026 * argument and that is an integer. If there are two such numbers,
7027 * then the one that is even is returned.
7028 */
7029void
7030xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7031 double f;
7032
7033 CHECK_ARITY(1);
7034 CAST_TO_NUMBER;
7035 CHECK_TYPE(XPATH_NUMBER);
7036
Daniel Veillardcda96922001-08-21 10:56:31 +00007037 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
7038 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
7039 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007040 (ctxt->value->floatval == 0.0))
7041 return;
7042
Owen Taylor3473f882001-02-23 17:55:21 +00007043 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007044 if (ctxt->value->floatval < 0) {
7045 if (ctxt->value->floatval < f - 0.5)
7046 ctxt->value->floatval = f - 1;
7047 else
7048 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007049 if (ctxt->value->floatval == 0)
7050 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007051 } else {
7052 if (ctxt->value->floatval < f + 0.5)
7053 ctxt->value->floatval = f;
7054 else
7055 ctxt->value->floatval = f + 1;
7056 }
Owen Taylor3473f882001-02-23 17:55:21 +00007057}
7058
7059/************************************************************************
7060 * *
7061 * The Parser *
7062 * *
7063 ************************************************************************/
7064
7065/*
7066 * a couple of forward declarations since we use a recursive call based
7067 * implementation.
7068 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007069static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007070static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007071static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007072static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00007073static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
7074 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00007075
7076/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00007077 * xmlXPathCurrentChar:
7078 * @ctxt: the XPath parser context
7079 * @cur: pointer to the beginning of the char
7080 * @len: pointer to the length of the char read
7081 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007082 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00007083 * bytes in the input buffer.
7084 *
Daniel Veillard60087f32001-10-10 09:45:09 +00007085 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00007086 */
7087
7088static int
7089xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
7090 unsigned char c;
7091 unsigned int val;
7092 const xmlChar *cur;
7093
7094 if (ctxt == NULL)
7095 return(0);
7096 cur = ctxt->cur;
7097
7098 /*
7099 * We are supposed to handle UTF8, check it's valid
7100 * From rfc2044: encoding of the Unicode values on UTF-8:
7101 *
7102 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
7103 * 0000 0000-0000 007F 0xxxxxxx
7104 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
7105 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
7106 *
7107 * Check for the 0x110000 limit too
7108 */
7109 c = *cur;
7110 if (c & 0x80) {
7111 if ((cur[1] & 0xc0) != 0x80)
7112 goto encoding_error;
7113 if ((c & 0xe0) == 0xe0) {
7114
7115 if ((cur[2] & 0xc0) != 0x80)
7116 goto encoding_error;
7117 if ((c & 0xf0) == 0xf0) {
7118 if (((c & 0xf8) != 0xf0) ||
7119 ((cur[3] & 0xc0) != 0x80))
7120 goto encoding_error;
7121 /* 4-byte code */
7122 *len = 4;
7123 val = (cur[0] & 0x7) << 18;
7124 val |= (cur[1] & 0x3f) << 12;
7125 val |= (cur[2] & 0x3f) << 6;
7126 val |= cur[3] & 0x3f;
7127 } else {
7128 /* 3-byte code */
7129 *len = 3;
7130 val = (cur[0] & 0xf) << 12;
7131 val |= (cur[1] & 0x3f) << 6;
7132 val |= cur[2] & 0x3f;
7133 }
7134 } else {
7135 /* 2-byte code */
7136 *len = 2;
7137 val = (cur[0] & 0x1f) << 6;
7138 val |= cur[1] & 0x3f;
7139 }
7140 if (!IS_CHAR(val)) {
7141 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
7142 }
7143 return(val);
7144 } else {
7145 /* 1-byte code */
7146 *len = 1;
7147 return((int) *cur);
7148 }
7149encoding_error:
7150 /*
7151 * If we detect an UTF8 error that probably mean that the
7152 * input encoding didn't get properly advertized in the
7153 * declaration header. Report the error and switch the encoding
7154 * to ISO-Latin-1 (if you don't like this policy, just declare the
7155 * encoding !)
7156 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00007157 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00007158 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007159}
7160
7161/**
Owen Taylor3473f882001-02-23 17:55:21 +00007162 * xmlXPathParseNCName:
7163 * @ctxt: the XPath Parser context
7164 *
7165 * parse an XML namespace non qualified name.
7166 *
7167 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7168 *
7169 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7170 * CombiningChar | Extender
7171 *
7172 * Returns the namespace name or NULL
7173 */
7174
7175xmlChar *
7176xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00007177 const xmlChar *in;
7178 xmlChar *ret;
7179 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007180
Daniel Veillard2156a562001-04-28 12:24:34 +00007181 /*
7182 * Accelerator for simple ASCII names
7183 */
7184 in = ctxt->cur;
7185 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7186 ((*in >= 0x41) && (*in <= 0x5A)) ||
7187 (*in == '_')) {
7188 in++;
7189 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7190 ((*in >= 0x41) && (*in <= 0x5A)) ||
7191 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00007192 (*in == '_') || (*in == '.') ||
7193 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00007194 in++;
7195 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7196 (*in == '[') || (*in == ']') || (*in == ':') ||
7197 (*in == '@') || (*in == '*')) {
7198 count = in - ctxt->cur;
7199 if (count == 0)
7200 return(NULL);
7201 ret = xmlStrndup(ctxt->cur, count);
7202 ctxt->cur = in;
7203 return(ret);
7204 }
7205 }
7206 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00007207}
7208
Daniel Veillard2156a562001-04-28 12:24:34 +00007209
Owen Taylor3473f882001-02-23 17:55:21 +00007210/**
7211 * xmlXPathParseQName:
7212 * @ctxt: the XPath Parser context
7213 * @prefix: a xmlChar **
7214 *
7215 * parse an XML qualified name
7216 *
7217 * [NS 5] QName ::= (Prefix ':')? LocalPart
7218 *
7219 * [NS 6] Prefix ::= NCName
7220 *
7221 * [NS 7] LocalPart ::= NCName
7222 *
7223 * Returns the function returns the local part, and prefix is updated
7224 * to get the Prefix if any.
7225 */
7226
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007227static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007228xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7229 xmlChar *ret = NULL;
7230
7231 *prefix = NULL;
7232 ret = xmlXPathParseNCName(ctxt);
7233 if (CUR == ':') {
7234 *prefix = ret;
7235 NEXT;
7236 ret = xmlXPathParseNCName(ctxt);
7237 }
7238 return(ret);
7239}
7240
7241/**
7242 * xmlXPathParseName:
7243 * @ctxt: the XPath Parser context
7244 *
7245 * parse an XML name
7246 *
7247 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7248 * CombiningChar | Extender
7249 *
7250 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7251 *
7252 * Returns the namespace name or NULL
7253 */
7254
7255xmlChar *
7256xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007257 const xmlChar *in;
7258 xmlChar *ret;
7259 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007260
Daniel Veillard61d80a22001-04-27 17:13:01 +00007261 /*
7262 * Accelerator for simple ASCII names
7263 */
7264 in = ctxt->cur;
7265 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7266 ((*in >= 0x41) && (*in <= 0x5A)) ||
7267 (*in == '_') || (*in == ':')) {
7268 in++;
7269 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7270 ((*in >= 0x41) && (*in <= 0x5A)) ||
7271 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00007272 (*in == '_') || (*in == '-') ||
7273 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00007274 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007275 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007276 count = in - ctxt->cur;
7277 ret = xmlStrndup(ctxt->cur, count);
7278 ctxt->cur = in;
7279 return(ret);
7280 }
7281 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007282 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00007283}
7284
Daniel Veillard61d80a22001-04-27 17:13:01 +00007285static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00007286xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007287 xmlChar buf[XML_MAX_NAMELEN + 5];
7288 int len = 0, l;
7289 int c;
7290
7291 /*
7292 * Handler for more complex cases
7293 */
7294 c = CUR_CHAR(l);
7295 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00007296 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7297 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00007298 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00007299 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007300 return(NULL);
7301 }
7302
7303 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7304 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7305 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007306 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007307 (IS_COMBINING(c)) ||
7308 (IS_EXTENDER(c)))) {
7309 COPY_BUF(l,buf,len,c);
7310 NEXTL(l);
7311 c = CUR_CHAR(l);
7312 if (len >= XML_MAX_NAMELEN) {
7313 /*
7314 * Okay someone managed to make a huge name, so he's ready to pay
7315 * for the processing speed.
7316 */
7317 xmlChar *buffer;
7318 int max = len * 2;
7319
7320 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
7321 if (buffer == NULL) {
7322 XP_ERROR0(XPATH_MEMORY_ERROR);
7323 }
7324 memcpy(buffer, buf, len);
7325 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7326 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007327 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007328 (IS_COMBINING(c)) ||
7329 (IS_EXTENDER(c))) {
7330 if (len + 10 > max) {
7331 max *= 2;
7332 buffer = (xmlChar *) xmlRealloc(buffer,
7333 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007334 if (buffer == NULL) {
7335 XP_ERROR0(XPATH_MEMORY_ERROR);
7336 }
7337 }
7338 COPY_BUF(l,buffer,len,c);
7339 NEXTL(l);
7340 c = CUR_CHAR(l);
7341 }
7342 buffer[len] = 0;
7343 return(buffer);
7344 }
7345 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007346 if (len == 0)
7347 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007348 return(xmlStrndup(buf, len));
7349}
Daniel Veillard3cd72402002-05-13 10:33:30 +00007350
7351#define MAX_FRAC 20
7352
7353static double my_pow10[MAX_FRAC] = {
7354 1.0, 10.0, 100.0, 1000.0, 10000.0,
7355 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7356 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7357 100000000000000.0,
7358 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
7359 1000000000000000000.0, 10000000000000000000.0
7360};
7361
Owen Taylor3473f882001-02-23 17:55:21 +00007362/**
7363 * xmlXPathStringEvalNumber:
7364 * @str: A string to scan
7365 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00007366 * [30a] Float ::= Number ('e' Digits?)?
7367 *
Owen Taylor3473f882001-02-23 17:55:21 +00007368 * [30] Number ::= Digits ('.' Digits?)?
7369 * | '.' Digits
7370 * [31] Digits ::= [0-9]+
7371 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007372 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00007373 * In complement of the Number expression, this function also handles
7374 * negative values : '-' Number.
7375 *
7376 * Returns the double value.
7377 */
7378double
7379xmlXPathStringEvalNumber(const xmlChar *str) {
7380 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00007381 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007382 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007383 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007384 int exponent = 0;
7385 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007386#ifdef __GNUC__
7387 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007388 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007389#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00007390 if (cur == NULL) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00007391 while (IS_BLANK(*cur)) cur++;
7392 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7393 return(xmlXPathNAN);
7394 }
7395 if (*cur == '-') {
7396 isneg = 1;
7397 cur++;
7398 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007399
7400#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007401 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007402 * tmp/temp is a workaround against a gcc compiler bug
7403 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007404 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007405 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007406 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007407 ret = ret * 10;
7408 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00007409 ok = 1;
7410 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00007411 temp = (double) tmp;
7412 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007413 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007414#else
Daniel Veillard7b416132002-03-07 08:36:03 +00007415 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007416 while ((*cur >= '0') && (*cur <= '9')) {
7417 ret = ret * 10 + (*cur - '0');
7418 ok = 1;
7419 cur++;
7420 }
7421#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007422
Owen Taylor3473f882001-02-23 17:55:21 +00007423 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007424 int v, frac = 0;
7425 double fraction = 0;
7426
Owen Taylor3473f882001-02-23 17:55:21 +00007427 cur++;
7428 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7429 return(xmlXPathNAN);
7430 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007431 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
7432 v = (*cur - '0');
7433 fraction = fraction * 10 + v;
7434 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007435 cur++;
7436 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007437 fraction /= my_pow10[frac];
7438 ret = ret + fraction;
7439 while ((*cur >= '0') && (*cur <= '9'))
7440 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007441 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007442 if ((*cur == 'e') || (*cur == 'E')) {
7443 cur++;
7444 if (*cur == '-') {
7445 is_exponent_negative = 1;
7446 cur++;
7447 }
7448 while ((*cur >= '0') && (*cur <= '9')) {
7449 exponent = exponent * 10 + (*cur - '0');
7450 cur++;
7451 }
7452 }
Owen Taylor3473f882001-02-23 17:55:21 +00007453 while (IS_BLANK(*cur)) cur++;
7454 if (*cur != 0) return(xmlXPathNAN);
7455 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007456 if (is_exponent_negative) exponent = -exponent;
7457 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007458 return(ret);
7459}
7460
7461/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007462 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007463 * @ctxt: the XPath Parser context
7464 *
7465 * [30] Number ::= Digits ('.' Digits?)?
7466 * | '.' Digits
7467 * [31] Digits ::= [0-9]+
7468 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007469 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007470 *
7471 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007472static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007473xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7474{
Owen Taylor3473f882001-02-23 17:55:21 +00007475 double ret = 0.0;
7476 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007477 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007478 int exponent = 0;
7479 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007480#ifdef __GNUC__
7481 unsigned long tmp = 0;
7482 double temp;
7483#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007484
7485 CHECK_ERROR;
7486 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7487 XP_ERROR(XPATH_NUMBER_ERROR);
7488 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007489#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007490 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007491 * tmp/temp is a workaround against a gcc compiler bug
7492 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007493 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007494 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007495 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007496 ret = ret * 10;
7497 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007498 ok = 1;
7499 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007500 temp = (double) tmp;
7501 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007502 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007503#else
7504 ret = 0;
7505 while ((CUR >= '0') && (CUR <= '9')) {
7506 ret = ret * 10 + (CUR - '0');
7507 ok = 1;
7508 NEXT;
7509 }
7510#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007511 if (CUR == '.') {
7512 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007513 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7514 XP_ERROR(XPATH_NUMBER_ERROR);
7515 }
7516 while ((CUR >= '0') && (CUR <= '9')) {
7517 mult /= 10;
7518 ret = ret + (CUR - '0') * mult;
7519 NEXT;
7520 }
Owen Taylor3473f882001-02-23 17:55:21 +00007521 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007522 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007523 NEXT;
7524 if (CUR == '-') {
7525 is_exponent_negative = 1;
7526 NEXT;
7527 }
7528 while ((CUR >= '0') && (CUR <= '9')) {
7529 exponent = exponent * 10 + (CUR - '0');
7530 NEXT;
7531 }
7532 if (is_exponent_negative)
7533 exponent = -exponent;
7534 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007535 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007536 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007537 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007538}
7539
7540/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007541 * xmlXPathParseLiteral:
7542 * @ctxt: the XPath Parser context
7543 *
7544 * Parse a Literal
7545 *
7546 * [29] Literal ::= '"' [^"]* '"'
7547 * | "'" [^']* "'"
7548 *
7549 * Returns the value found or NULL in case of error
7550 */
7551static xmlChar *
7552xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7553 const xmlChar *q;
7554 xmlChar *ret = NULL;
7555
7556 if (CUR == '"') {
7557 NEXT;
7558 q = CUR_PTR;
7559 while ((IS_CHAR(CUR)) && (CUR != '"'))
7560 NEXT;
7561 if (!IS_CHAR(CUR)) {
7562 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7563 } else {
7564 ret = xmlStrndup(q, CUR_PTR - q);
7565 NEXT;
7566 }
7567 } else if (CUR == '\'') {
7568 NEXT;
7569 q = CUR_PTR;
7570 while ((IS_CHAR(CUR)) && (CUR != '\''))
7571 NEXT;
7572 if (!IS_CHAR(CUR)) {
7573 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7574 } else {
7575 ret = xmlStrndup(q, CUR_PTR - q);
7576 NEXT;
7577 }
7578 } else {
7579 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7580 }
7581 return(ret);
7582}
7583
7584/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007585 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007586 * @ctxt: the XPath Parser context
7587 *
7588 * Parse a Literal and push it on the stack.
7589 *
7590 * [29] Literal ::= '"' [^"]* '"'
7591 * | "'" [^']* "'"
7592 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007593 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007594 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007595static void
7596xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007597 const xmlChar *q;
7598 xmlChar *ret = NULL;
7599
7600 if (CUR == '"') {
7601 NEXT;
7602 q = CUR_PTR;
7603 while ((IS_CHAR(CUR)) && (CUR != '"'))
7604 NEXT;
7605 if (!IS_CHAR(CUR)) {
7606 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7607 } else {
7608 ret = xmlStrndup(q, CUR_PTR - q);
7609 NEXT;
7610 }
7611 } else if (CUR == '\'') {
7612 NEXT;
7613 q = CUR_PTR;
7614 while ((IS_CHAR(CUR)) && (CUR != '\''))
7615 NEXT;
7616 if (!IS_CHAR(CUR)) {
7617 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7618 } else {
7619 ret = xmlStrndup(q, CUR_PTR - q);
7620 NEXT;
7621 }
7622 } else {
7623 XP_ERROR(XPATH_START_LITERAL_ERROR);
7624 }
7625 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007626 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7627 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007628 xmlFree(ret);
7629}
7630
7631/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007632 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007633 * @ctxt: the XPath Parser context
7634 *
7635 * Parse a VariableReference, evaluate it and push it on the stack.
7636 *
7637 * The variable bindings consist of a mapping from variable names
7638 * to variable values. The value of a variable is an object, which
7639 * of any of the types that are possible for the value of an expression,
7640 * and may also be of additional types not specified here.
7641 *
7642 * Early evaluation is possible since:
7643 * The variable bindings [...] used to evaluate a subexpression are
7644 * always the same as those used to evaluate the containing expression.
7645 *
7646 * [36] VariableReference ::= '$' QName
7647 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007648static void
7649xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007650 xmlChar *name;
7651 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007652
7653 SKIP_BLANKS;
7654 if (CUR != '$') {
7655 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7656 }
7657 NEXT;
7658 name = xmlXPathParseQName(ctxt, &prefix);
7659 if (name == NULL) {
7660 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7661 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007662 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007663 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7664 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007665 SKIP_BLANKS;
7666}
7667
7668/**
7669 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +00007670 * @name: a name string
7671 *
7672 * Is the name given a NodeType one.
7673 *
7674 * [38] NodeType ::= 'comment'
7675 * | 'text'
7676 * | 'processing-instruction'
7677 * | 'node'
7678 *
7679 * Returns 1 if true 0 otherwise
7680 */
7681int
7682xmlXPathIsNodeType(const xmlChar *name) {
7683 if (name == NULL)
7684 return(0);
7685
Daniel Veillard1971ee22002-01-31 20:29:19 +00007686 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007687 return(1);
7688 if (xmlStrEqual(name, BAD_CAST "text"))
7689 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007690 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007691 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007692 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007693 return(1);
7694 return(0);
7695}
7696
7697/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007698 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007699 * @ctxt: the XPath Parser context
7700 *
7701 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7702 * [17] Argument ::= Expr
7703 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007704 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007705 * pushed on the stack
7706 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007707static void
7708xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007709 xmlChar *name;
7710 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007711 int nbargs = 0;
7712
7713 name = xmlXPathParseQName(ctxt, &prefix);
7714 if (name == NULL) {
7715 XP_ERROR(XPATH_EXPR_ERROR);
7716 }
7717 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007718#ifdef DEBUG_EXPR
7719 if (prefix == NULL)
7720 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7721 name);
7722 else
7723 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7724 prefix, name);
7725#endif
7726
Owen Taylor3473f882001-02-23 17:55:21 +00007727 if (CUR != '(') {
7728 XP_ERROR(XPATH_EXPR_ERROR);
7729 }
7730 NEXT;
7731 SKIP_BLANKS;
7732
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007733 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +00007734 if (CUR != ')') {
7735 while (CUR != 0) {
7736 int op1 = ctxt->comp->last;
7737 ctxt->comp->last = -1;
7738 xmlXPathCompileExpr(ctxt);
7739 CHECK_ERROR;
7740 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
7741 nbargs++;
7742 if (CUR == ')') break;
7743 if (CUR != ',') {
7744 XP_ERROR(XPATH_EXPR_ERROR);
7745 }
7746 NEXT;
7747 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007748 }
Owen Taylor3473f882001-02-23 17:55:21 +00007749 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007750 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7751 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007752 NEXT;
7753 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007754}
7755
7756/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007757 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007758 * @ctxt: the XPath Parser context
7759 *
7760 * [15] PrimaryExpr ::= VariableReference
7761 * | '(' Expr ')'
7762 * | Literal
7763 * | Number
7764 * | FunctionCall
7765 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007766 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007767 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007768static void
7769xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007770 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007771 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007772 else if (CUR == '(') {
7773 NEXT;
7774 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007775 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007776 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00007777 if (CUR != ')') {
7778 XP_ERROR(XPATH_EXPR_ERROR);
7779 }
7780 NEXT;
7781 SKIP_BLANKS;
Daniel Veillard01917aa2002-04-10 11:30:41 +00007782 } else if (IS_DIGIT(CUR) || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007783 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007784 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007785 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007786 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007787 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007788 }
7789 SKIP_BLANKS;
7790}
7791
7792/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007793 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007794 * @ctxt: the XPath Parser context
7795 *
7796 * [20] FilterExpr ::= PrimaryExpr
7797 * | FilterExpr Predicate
7798 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007799 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007800 * Square brackets are used to filter expressions in the same way that
7801 * they are used in location paths. It is an error if the expression to
7802 * be filtered does not evaluate to a node-set. The context node list
7803 * used for evaluating the expression in square brackets is the node-set
7804 * to be filtered listed in document order.
7805 */
7806
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007807static void
7808xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
7809 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007810 CHECK_ERROR;
7811 SKIP_BLANKS;
7812
7813 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007814 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00007815 SKIP_BLANKS;
7816 }
7817
7818
7819}
7820
7821/**
7822 * xmlXPathScanName:
7823 * @ctxt: the XPath Parser context
7824 *
7825 * Trickery: parse an XML name but without consuming the input flow
7826 * Needed to avoid insanity in the parser state.
7827 *
7828 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7829 * CombiningChar | Extender
7830 *
7831 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7832 *
7833 * [6] Names ::= Name (S Name)*
7834 *
7835 * Returns the Name parsed or NULL
7836 */
7837
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007838static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007839xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7840 xmlChar buf[XML_MAX_NAMELEN];
7841 int len = 0;
7842
7843 SKIP_BLANKS;
7844 if (!IS_LETTER(CUR) && (CUR != '_') &&
7845 (CUR != ':')) {
7846 return(NULL);
7847 }
7848
7849 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7850 (NXT(len) == '.') || (NXT(len) == '-') ||
7851 (NXT(len) == '_') || (NXT(len) == ':') ||
7852 (IS_COMBINING(NXT(len))) ||
7853 (IS_EXTENDER(NXT(len)))) {
7854 buf[len] = NXT(len);
7855 len++;
7856 if (len >= XML_MAX_NAMELEN) {
7857 xmlGenericError(xmlGenericErrorContext,
7858 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
7859 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7860 (NXT(len) == '.') || (NXT(len) == '-') ||
7861 (NXT(len) == '_') || (NXT(len) == ':') ||
7862 (IS_COMBINING(NXT(len))) ||
7863 (IS_EXTENDER(NXT(len))))
7864 len++;
7865 break;
7866 }
7867 }
7868 return(xmlStrndup(buf, len));
7869}
7870
7871/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007872 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007873 * @ctxt: the XPath Parser context
7874 *
7875 * [19] PathExpr ::= LocationPath
7876 * | FilterExpr
7877 * | FilterExpr '/' RelativeLocationPath
7878 * | FilterExpr '//' RelativeLocationPath
7879 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007880 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007881 * The / operator and // operators combine an arbitrary expression
7882 * and a relative location path. It is an error if the expression
7883 * does not evaluate to a node-set.
7884 * The / operator does composition in the same way as when / is
7885 * used in a location path. As in location paths, // is short for
7886 * /descendant-or-self::node()/.
7887 */
7888
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007889static void
7890xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007891 int lc = 1; /* Should we branch to LocationPath ? */
7892 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7893
7894 SKIP_BLANKS;
7895 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
Daniel Veillard01917aa2002-04-10 11:30:41 +00007896 (CUR == '\'') || (CUR == '"') || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00007897 lc = 0;
7898 } else if (CUR == '*') {
7899 /* relative or absolute location path */
7900 lc = 1;
7901 } else if (CUR == '/') {
7902 /* relative or absolute location path */
7903 lc = 1;
7904 } else if (CUR == '@') {
7905 /* relative abbreviated attribute location path */
7906 lc = 1;
7907 } else if (CUR == '.') {
7908 /* relative abbreviated attribute location path */
7909 lc = 1;
7910 } else {
7911 /*
7912 * Problem is finding if we have a name here whether it's:
7913 * - a nodetype
7914 * - a function call in which case it's followed by '('
7915 * - an axis in which case it's followed by ':'
7916 * - a element name
7917 * We do an a priori analysis here rather than having to
7918 * maintain parsed token content through the recursive function
7919 * calls. This looks uglier but makes the code quite easier to
7920 * read/write/debug.
7921 */
7922 SKIP_BLANKS;
7923 name = xmlXPathScanName(ctxt);
7924 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7925#ifdef DEBUG_STEP
7926 xmlGenericError(xmlGenericErrorContext,
7927 "PathExpr: Axis\n");
7928#endif
7929 lc = 1;
7930 xmlFree(name);
7931 } else if (name != NULL) {
7932 int len =xmlStrlen(name);
7933 int blank = 0;
7934
7935
7936 while (NXT(len) != 0) {
7937 if (NXT(len) == '/') {
7938 /* element name */
7939#ifdef DEBUG_STEP
7940 xmlGenericError(xmlGenericErrorContext,
7941 "PathExpr: AbbrRelLocation\n");
7942#endif
7943 lc = 1;
7944 break;
7945 } else if (IS_BLANK(NXT(len))) {
7946 /* skip to next */
7947 blank = 1;
7948 } else if (NXT(len) == ':') {
7949#ifdef DEBUG_STEP
7950 xmlGenericError(xmlGenericErrorContext,
7951 "PathExpr: AbbrRelLocation\n");
7952#endif
7953 lc = 1;
7954 break;
7955 } else if ((NXT(len) == '(')) {
7956 /* Note Type or Function */
7957 if (xmlXPathIsNodeType(name)) {
7958#ifdef DEBUG_STEP
7959 xmlGenericError(xmlGenericErrorContext,
7960 "PathExpr: Type search\n");
7961#endif
7962 lc = 1;
7963 } else {
7964#ifdef DEBUG_STEP
7965 xmlGenericError(xmlGenericErrorContext,
7966 "PathExpr: function call\n");
7967#endif
7968 lc = 0;
7969 }
7970 break;
7971 } else if ((NXT(len) == '[')) {
7972 /* element name */
7973#ifdef DEBUG_STEP
7974 xmlGenericError(xmlGenericErrorContext,
7975 "PathExpr: AbbrRelLocation\n");
7976#endif
7977 lc = 1;
7978 break;
7979 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
7980 (NXT(len) == '=')) {
7981 lc = 1;
7982 break;
7983 } else {
7984 lc = 1;
7985 break;
7986 }
7987 len++;
7988 }
7989 if (NXT(len) == 0) {
7990#ifdef DEBUG_STEP
7991 xmlGenericError(xmlGenericErrorContext,
7992 "PathExpr: AbbrRelLocation\n");
7993#endif
7994 /* element name */
7995 lc = 1;
7996 }
7997 xmlFree(name);
7998 } else {
7999 /* make sure all cases are covered explicitely */
8000 XP_ERROR(XPATH_EXPR_ERROR);
8001 }
8002 }
8003
8004 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008005 if (CUR == '/') {
8006 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8007 } else {
8008 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008009 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008010 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008011 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008012 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008013 CHECK_ERROR;
8014 if ((CUR == '/') && (NXT(1) == '/')) {
8015 SKIP(2);
8016 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008017
8018 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8019 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8020 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
8021
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008022 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008023 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008024 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008025 }
8026 }
8027 SKIP_BLANKS;
8028}
8029
8030/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008031 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008032 * @ctxt: the XPath Parser context
8033 *
8034 * [18] UnionExpr ::= PathExpr
8035 * | UnionExpr '|' PathExpr
8036 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008037 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008038 */
8039
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008040static void
8041xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8042 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008043 CHECK_ERROR;
8044 SKIP_BLANKS;
8045 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008046 int op1 = ctxt->comp->last;
8047 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008048
8049 NEXT;
8050 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008051 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008052
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008053 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8054
Owen Taylor3473f882001-02-23 17:55:21 +00008055 SKIP_BLANKS;
8056 }
Owen Taylor3473f882001-02-23 17:55:21 +00008057}
8058
8059/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008060 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008061 * @ctxt: the XPath Parser context
8062 *
8063 * [27] UnaryExpr ::= UnionExpr
8064 * | '-' UnaryExpr
8065 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008066 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008067 */
8068
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008069static void
8070xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008071 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008072 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008073
8074 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00008075 while (CUR == '-') {
8076 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008077 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008078 NEXT;
8079 SKIP_BLANKS;
8080 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008081
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008082 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008083 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008084 if (found) {
8085 if (minus)
8086 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8087 else
8088 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008089 }
8090}
8091
8092/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008093 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008094 * @ctxt: the XPath Parser context
8095 *
8096 * [26] MultiplicativeExpr ::= UnaryExpr
8097 * | MultiplicativeExpr MultiplyOperator UnaryExpr
8098 * | MultiplicativeExpr 'div' UnaryExpr
8099 * | MultiplicativeExpr 'mod' UnaryExpr
8100 * [34] MultiplyOperator ::= '*'
8101 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008102 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008103 */
8104
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008105static void
8106xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8107 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008108 CHECK_ERROR;
8109 SKIP_BLANKS;
8110 while ((CUR == '*') ||
8111 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8112 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8113 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008114 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008115
8116 if (CUR == '*') {
8117 op = 0;
8118 NEXT;
8119 } else if (CUR == 'd') {
8120 op = 1;
8121 SKIP(3);
8122 } else if (CUR == 'm') {
8123 op = 2;
8124 SKIP(3);
8125 }
8126 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008127 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008128 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008129 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008130 SKIP_BLANKS;
8131 }
8132}
8133
8134/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008135 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008136 * @ctxt: the XPath Parser context
8137 *
8138 * [25] AdditiveExpr ::= MultiplicativeExpr
8139 * | AdditiveExpr '+' MultiplicativeExpr
8140 * | AdditiveExpr '-' MultiplicativeExpr
8141 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008142 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008143 */
8144
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008145static void
8146xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008147
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008148 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008149 CHECK_ERROR;
8150 SKIP_BLANKS;
8151 while ((CUR == '+') || (CUR == '-')) {
8152 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008153 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008154
8155 if (CUR == '+') plus = 1;
8156 else plus = 0;
8157 NEXT;
8158 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008159 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008160 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008161 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008162 SKIP_BLANKS;
8163 }
8164}
8165
8166/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008167 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008168 * @ctxt: the XPath Parser context
8169 *
8170 * [24] RelationalExpr ::= AdditiveExpr
8171 * | RelationalExpr '<' AdditiveExpr
8172 * | RelationalExpr '>' AdditiveExpr
8173 * | RelationalExpr '<=' AdditiveExpr
8174 * | RelationalExpr '>=' AdditiveExpr
8175 *
8176 * A <= B > C is allowed ? Answer from James, yes with
8177 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8178 * which is basically what got implemented.
8179 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008180 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00008181 * on the stack
8182 */
8183
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008184static void
8185xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8186 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008187 CHECK_ERROR;
8188 SKIP_BLANKS;
8189 while ((CUR == '<') ||
8190 (CUR == '>') ||
8191 ((CUR == '<') && (NXT(1) == '=')) ||
8192 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008193 int inf, strict;
8194 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008195
8196 if (CUR == '<') inf = 1;
8197 else inf = 0;
8198 if (NXT(1) == '=') strict = 0;
8199 else strict = 1;
8200 NEXT;
8201 if (!strict) NEXT;
8202 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008203 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008204 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008205 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00008206 SKIP_BLANKS;
8207 }
8208}
8209
8210/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008211 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008212 * @ctxt: the XPath Parser context
8213 *
8214 * [23] EqualityExpr ::= RelationalExpr
8215 * | EqualityExpr '=' RelationalExpr
8216 * | EqualityExpr '!=' RelationalExpr
8217 *
8218 * A != B != C is allowed ? Answer from James, yes with
8219 * (RelationalExpr = RelationalExpr) = RelationalExpr
8220 * (RelationalExpr != RelationalExpr) != RelationalExpr
8221 * which is basically what got implemented.
8222 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008223 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008224 *
8225 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008226static void
8227xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8228 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008229 CHECK_ERROR;
8230 SKIP_BLANKS;
8231 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008232 int eq;
8233 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008234
8235 if (CUR == '=') eq = 1;
8236 else eq = 0;
8237 NEXT;
8238 if (!eq) NEXT;
8239 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008240 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008241 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008242 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008243 SKIP_BLANKS;
8244 }
8245}
8246
8247/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008248 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008249 * @ctxt: the XPath Parser context
8250 *
8251 * [22] AndExpr ::= EqualityExpr
8252 * | AndExpr 'and' EqualityExpr
8253 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008254 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008255 *
8256 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008257static void
8258xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8259 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008260 CHECK_ERROR;
8261 SKIP_BLANKS;
8262 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008263 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008264 SKIP(3);
8265 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008266 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008267 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008268 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008269 SKIP_BLANKS;
8270 }
8271}
8272
8273/**
Daniel Veillard591b4be2003-02-09 23:33:36 +00008274 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008275 * @ctxt: the XPath Parser context
8276 *
8277 * [14] Expr ::= OrExpr
8278 * [21] OrExpr ::= AndExpr
8279 * | OrExpr 'or' AndExpr
8280 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008281 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00008282 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008283static void
8284xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8285 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008286 CHECK_ERROR;
8287 SKIP_BLANKS;
8288 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008289 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008290 SKIP(2);
8291 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008292 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008293 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008294 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8295 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00008296 SKIP_BLANKS;
8297 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008298 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8299 /* more ops could be optimized too */
8300 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8301 }
Owen Taylor3473f882001-02-23 17:55:21 +00008302}
8303
8304/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008305 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00008306 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008307 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00008308 *
8309 * [8] Predicate ::= '[' PredicateExpr ']'
8310 * [9] PredicateExpr ::= Expr
8311 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008312 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008313 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008314static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008315xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008316 int op1 = ctxt->comp->last;
8317
8318 SKIP_BLANKS;
8319 if (CUR != '[') {
8320 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8321 }
8322 NEXT;
8323 SKIP_BLANKS;
8324
8325 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008326 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008327 CHECK_ERROR;
8328
8329 if (CUR != ']') {
8330 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8331 }
8332
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008333 if (filter)
8334 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8335 else
8336 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008337
8338 NEXT;
8339 SKIP_BLANKS;
8340}
8341
8342/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008343 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00008344 * @ctxt: the XPath Parser context
8345 * @test: pointer to a xmlXPathTestVal
8346 * @type: pointer to a xmlXPathTypeVal
8347 * @prefix: placeholder for a possible name prefix
8348 *
8349 * [7] NodeTest ::= NameTest
8350 * | NodeType '(' ')'
8351 * | 'processing-instruction' '(' Literal ')'
8352 *
8353 * [37] NameTest ::= '*'
8354 * | NCName ':' '*'
8355 * | QName
8356 * [38] NodeType ::= 'comment'
8357 * | 'text'
8358 * | 'processing-instruction'
8359 * | 'node'
8360 *
8361 * Returns the name found and update @test, @type and @prefix appropriately
8362 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008363static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008364xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8365 xmlXPathTypeVal *type, const xmlChar **prefix,
8366 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008367 int blanks;
8368
8369 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8370 STRANGE;
8371 return(NULL);
8372 }
8373 *type = 0;
8374 *test = 0;
8375 *prefix = NULL;
8376 SKIP_BLANKS;
8377
8378 if ((name == NULL) && (CUR == '*')) {
8379 /*
8380 * All elements
8381 */
8382 NEXT;
8383 *test = NODE_TEST_ALL;
8384 return(NULL);
8385 }
8386
8387 if (name == NULL)
8388 name = xmlXPathParseNCName(ctxt);
8389 if (name == NULL) {
8390 XP_ERROR0(XPATH_EXPR_ERROR);
8391 }
8392
8393 blanks = IS_BLANK(CUR);
8394 SKIP_BLANKS;
8395 if (CUR == '(') {
8396 NEXT;
8397 /*
8398 * NodeType or PI search
8399 */
8400 if (xmlStrEqual(name, BAD_CAST "comment"))
8401 *type = NODE_TYPE_COMMENT;
8402 else if (xmlStrEqual(name, BAD_CAST "node"))
8403 *type = NODE_TYPE_NODE;
8404 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8405 *type = NODE_TYPE_PI;
8406 else if (xmlStrEqual(name, BAD_CAST "text"))
8407 *type = NODE_TYPE_TEXT;
8408 else {
8409 if (name != NULL)
8410 xmlFree(name);
8411 XP_ERROR0(XPATH_EXPR_ERROR);
8412 }
8413
8414 *test = NODE_TEST_TYPE;
8415
8416 SKIP_BLANKS;
8417 if (*type == NODE_TYPE_PI) {
8418 /*
8419 * Specific case: search a PI by name.
8420 */
Owen Taylor3473f882001-02-23 17:55:21 +00008421 if (name != NULL)
8422 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008423 name = NULL;
8424 if (CUR != ')') {
8425 name = xmlXPathParseLiteral(ctxt);
8426 CHECK_ERROR 0;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00008427 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00008428 SKIP_BLANKS;
8429 }
Owen Taylor3473f882001-02-23 17:55:21 +00008430 }
8431 if (CUR != ')') {
8432 if (name != NULL)
8433 xmlFree(name);
8434 XP_ERROR0(XPATH_UNCLOSED_ERROR);
8435 }
8436 NEXT;
8437 return(name);
8438 }
8439 *test = NODE_TEST_NAME;
8440 if ((!blanks) && (CUR == ':')) {
8441 NEXT;
8442
8443 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008444 * Since currently the parser context don't have a
8445 * namespace list associated:
8446 * The namespace name for this prefix can be computed
8447 * only at evaluation time. The compilation is done
8448 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008449 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008450#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008451 *prefix = xmlXPathNsLookup(ctxt->context, name);
8452 if (name != NULL)
8453 xmlFree(name);
8454 if (*prefix == NULL) {
8455 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8456 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008457#else
8458 *prefix = name;
8459#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008460
8461 if (CUR == '*') {
8462 /*
8463 * All elements
8464 */
8465 NEXT;
8466 *test = NODE_TEST_ALL;
8467 return(NULL);
8468 }
8469
8470 name = xmlXPathParseNCName(ctxt);
8471 if (name == NULL) {
8472 XP_ERROR0(XPATH_EXPR_ERROR);
8473 }
8474 }
8475 return(name);
8476}
8477
8478/**
8479 * xmlXPathIsAxisName:
8480 * @name: a preparsed name token
8481 *
8482 * [6] AxisName ::= 'ancestor'
8483 * | 'ancestor-or-self'
8484 * | 'attribute'
8485 * | 'child'
8486 * | 'descendant'
8487 * | 'descendant-or-self'
8488 * | 'following'
8489 * | 'following-sibling'
8490 * | 'namespace'
8491 * | 'parent'
8492 * | 'preceding'
8493 * | 'preceding-sibling'
8494 * | 'self'
8495 *
8496 * Returns the axis or 0
8497 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008498static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008499xmlXPathIsAxisName(const xmlChar *name) {
8500 xmlXPathAxisVal ret = 0;
8501 switch (name[0]) {
8502 case 'a':
8503 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8504 ret = AXIS_ANCESTOR;
8505 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8506 ret = AXIS_ANCESTOR_OR_SELF;
8507 if (xmlStrEqual(name, BAD_CAST "attribute"))
8508 ret = AXIS_ATTRIBUTE;
8509 break;
8510 case 'c':
8511 if (xmlStrEqual(name, BAD_CAST "child"))
8512 ret = AXIS_CHILD;
8513 break;
8514 case 'd':
8515 if (xmlStrEqual(name, BAD_CAST "descendant"))
8516 ret = AXIS_DESCENDANT;
8517 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8518 ret = AXIS_DESCENDANT_OR_SELF;
8519 break;
8520 case 'f':
8521 if (xmlStrEqual(name, BAD_CAST "following"))
8522 ret = AXIS_FOLLOWING;
8523 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8524 ret = AXIS_FOLLOWING_SIBLING;
8525 break;
8526 case 'n':
8527 if (xmlStrEqual(name, BAD_CAST "namespace"))
8528 ret = AXIS_NAMESPACE;
8529 break;
8530 case 'p':
8531 if (xmlStrEqual(name, BAD_CAST "parent"))
8532 ret = AXIS_PARENT;
8533 if (xmlStrEqual(name, BAD_CAST "preceding"))
8534 ret = AXIS_PRECEDING;
8535 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8536 ret = AXIS_PRECEDING_SIBLING;
8537 break;
8538 case 's':
8539 if (xmlStrEqual(name, BAD_CAST "self"))
8540 ret = AXIS_SELF;
8541 break;
8542 }
8543 return(ret);
8544}
8545
8546/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008547 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008548 * @ctxt: the XPath Parser context
8549 *
8550 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8551 * | AbbreviatedStep
8552 *
8553 * [12] AbbreviatedStep ::= '.' | '..'
8554 *
8555 * [5] AxisSpecifier ::= AxisName '::'
8556 * | AbbreviatedAxisSpecifier
8557 *
8558 * [13] AbbreviatedAxisSpecifier ::= '@'?
8559 *
8560 * Modified for XPtr range support as:
8561 *
8562 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8563 * | AbbreviatedStep
8564 * | 'range-to' '(' Expr ')' Predicate*
8565 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008566 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008567 * A location step of . is short for self::node(). This is
8568 * particularly useful in conjunction with //. For example, the
8569 * location path .//para is short for
8570 * self::node()/descendant-or-self::node()/child::para
8571 * and so will select all para descendant elements of the context
8572 * node.
8573 * Similarly, a location step of .. is short for parent::node().
8574 * For example, ../title is short for parent::node()/child::title
8575 * and so will select the title children of the parent of the context
8576 * node.
8577 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008578static void
8579xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008580#ifdef LIBXML_XPTR_ENABLED
8581 int rangeto = 0;
8582 int op2 = -1;
8583#endif
8584
Owen Taylor3473f882001-02-23 17:55:21 +00008585 SKIP_BLANKS;
8586 if ((CUR == '.') && (NXT(1) == '.')) {
8587 SKIP(2);
8588 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008589 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8590 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008591 } else if (CUR == '.') {
8592 NEXT;
8593 SKIP_BLANKS;
8594 } else {
8595 xmlChar *name = NULL;
8596 const xmlChar *prefix = NULL;
8597 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008598 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008599 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008600 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008601
8602 /*
8603 * The modification needed for XPointer change to the production
8604 */
8605#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008606 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008607 name = xmlXPathParseNCName(ctxt);
8608 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008609 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008610 xmlFree(name);
8611 SKIP_BLANKS;
8612 if (CUR != '(') {
8613 XP_ERROR(XPATH_EXPR_ERROR);
8614 }
8615 NEXT;
8616 SKIP_BLANKS;
8617
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008618 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008619 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008620 CHECK_ERROR;
8621
8622 SKIP_BLANKS;
8623 if (CUR != ')') {
8624 XP_ERROR(XPATH_EXPR_ERROR);
8625 }
8626 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008627 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008628 goto eval_predicates;
8629 }
8630 }
8631#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008632 if (CUR == '*') {
8633 axis = AXIS_CHILD;
8634 } else {
8635 if (name == NULL)
8636 name = xmlXPathParseNCName(ctxt);
8637 if (name != NULL) {
8638 axis = xmlXPathIsAxisName(name);
8639 if (axis != 0) {
8640 SKIP_BLANKS;
8641 if ((CUR == ':') && (NXT(1) == ':')) {
8642 SKIP(2);
8643 xmlFree(name);
8644 name = NULL;
8645 } else {
8646 /* an element name can conflict with an axis one :-\ */
8647 axis = AXIS_CHILD;
8648 }
Owen Taylor3473f882001-02-23 17:55:21 +00008649 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008650 axis = AXIS_CHILD;
8651 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008652 } else if (CUR == '@') {
8653 NEXT;
8654 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008655 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008656 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008657 }
Owen Taylor3473f882001-02-23 17:55:21 +00008658 }
8659
8660 CHECK_ERROR;
8661
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008662 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008663 if (test == 0)
8664 return;
8665
8666#ifdef DEBUG_STEP
8667 xmlGenericError(xmlGenericErrorContext,
8668 "Basis : computing new set\n");
8669#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008670
Owen Taylor3473f882001-02-23 17:55:21 +00008671#ifdef DEBUG_STEP
8672 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008673 if (ctxt->value == NULL)
8674 xmlGenericError(xmlGenericErrorContext, "no value\n");
8675 else if (ctxt->value->nodesetval == NULL)
8676 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8677 else
8678 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008679#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008680
8681eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008682 op1 = ctxt->comp->last;
8683 ctxt->comp->last = -1;
8684
Owen Taylor3473f882001-02-23 17:55:21 +00008685 SKIP_BLANKS;
8686 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008687 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008688 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008689
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008690#ifdef LIBXML_XPTR_ENABLED
8691 if (rangeto) {
8692 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8693 } else
8694#endif
8695 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8696 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008697
Owen Taylor3473f882001-02-23 17:55:21 +00008698 }
8699#ifdef DEBUG_STEP
8700 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008701 if (ctxt->value == NULL)
8702 xmlGenericError(xmlGenericErrorContext, "no value\n");
8703 else if (ctxt->value->nodesetval == NULL)
8704 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8705 else
8706 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8707 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008708#endif
8709}
8710
8711/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008712 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008713 * @ctxt: the XPath Parser context
8714 *
8715 * [3] RelativeLocationPath ::= Step
8716 * | RelativeLocationPath '/' Step
8717 * | AbbreviatedRelativeLocationPath
8718 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8719 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008720 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008721 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008722static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008723xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008724(xmlXPathParserContextPtr ctxt) {
8725 SKIP_BLANKS;
8726 if ((CUR == '/') && (NXT(1) == '/')) {
8727 SKIP(2);
8728 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008729 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8730 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008731 } else if (CUR == '/') {
8732 NEXT;
8733 SKIP_BLANKS;
8734 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008735 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008736 SKIP_BLANKS;
8737 while (CUR == '/') {
8738 if ((CUR == '/') && (NXT(1) == '/')) {
8739 SKIP(2);
8740 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008741 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008742 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008743 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008744 } else if (CUR == '/') {
8745 NEXT;
8746 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008747 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008748 }
8749 SKIP_BLANKS;
8750 }
8751}
8752
8753/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008754 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008755 * @ctxt: the XPath Parser context
8756 *
8757 * [1] LocationPath ::= RelativeLocationPath
8758 * | AbsoluteLocationPath
8759 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8760 * | AbbreviatedAbsoluteLocationPath
8761 * [10] AbbreviatedAbsoluteLocationPath ::=
8762 * '//' RelativeLocationPath
8763 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008764 * Compile a location path
8765 *
Owen Taylor3473f882001-02-23 17:55:21 +00008766 * // is short for /descendant-or-self::node()/. For example,
8767 * //para is short for /descendant-or-self::node()/child::para and
8768 * so will select any para element in the document (even a para element
8769 * that is a document element will be selected by //para since the
8770 * document element node is a child of the root node); div//para is
8771 * short for div/descendant-or-self::node()/child::para and so will
8772 * select all para descendants of div children.
8773 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008774static void
8775xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008776 SKIP_BLANKS;
8777 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008778 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008779 } else {
8780 while (CUR == '/') {
8781 if ((CUR == '/') && (NXT(1) == '/')) {
8782 SKIP(2);
8783 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008784 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8785 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008786 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008787 } else if (CUR == '/') {
8788 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008789 SKIP_BLANKS;
8790 if ((CUR != 0 ) &&
8791 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
8792 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008793 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008794 }
8795 }
8796 }
8797}
8798
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008799/************************************************************************
8800 * *
8801 * XPath precompiled expression evaluation *
8802 * *
8803 ************************************************************************/
8804
Daniel Veillardf06307e2001-07-03 10:35:50 +00008805static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008806xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8807
8808/**
8809 * xmlXPathNodeCollectAndTest:
8810 * @ctxt: the XPath Parser context
8811 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008812 * @first: pointer to the first element in document order
8813 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008814 *
8815 * This is the function implementing a step: based on the current list
8816 * of nodes, it builds up a new list, looking at all nodes under that
8817 * axis and selecting them it also do the predicate filtering
8818 *
8819 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00008820 *
8821 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008822 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008823static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008824xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008825 xmlXPathStepOpPtr op,
8826 xmlNodePtr * first, xmlNodePtr * last)
8827{
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008828 xmlXPathAxisVal axis = op->value;
8829 xmlXPathTestVal test = op->value2;
8830 xmlXPathTypeVal type = op->value3;
8831 const xmlChar *prefix = op->value4;
8832 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008833 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008834
8835#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008836 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008837#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008838 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008839 xmlNodeSetPtr ret, list;
8840 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008841 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00008842 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008843 xmlNodePtr cur = NULL;
8844 xmlXPathObjectPtr obj;
8845 xmlNodeSetPtr nodelist;
8846 xmlNodePtr tmp;
8847
Daniel Veillardf06307e2001-07-03 10:35:50 +00008848 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008849 obj = valuePop(ctxt);
8850 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00008851 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008852 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008853 URI = xmlXPathNsLookup(ctxt->context, prefix);
8854 if (URI == NULL)
8855 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008856 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008857#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008858 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008859#endif
8860 switch (axis) {
8861 case AXIS_ANCESTOR:
8862#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008863 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008864#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008865 first = NULL;
8866 next = xmlXPathNextAncestor;
8867 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008868 case AXIS_ANCESTOR_OR_SELF:
8869#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008870 xmlGenericError(xmlGenericErrorContext,
8871 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008872#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008873 first = NULL;
8874 next = xmlXPathNextAncestorOrSelf;
8875 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008876 case AXIS_ATTRIBUTE:
8877#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008878 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008879#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008880 first = NULL;
8881 last = NULL;
8882 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00008883 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008884 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008885 case AXIS_CHILD:
8886#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008887 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008888#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008889 last = NULL;
8890 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00008891 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008892 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008893 case AXIS_DESCENDANT:
8894#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008895 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008896#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008897 last = NULL;
8898 next = xmlXPathNextDescendant;
8899 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008900 case AXIS_DESCENDANT_OR_SELF:
8901#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008902 xmlGenericError(xmlGenericErrorContext,
8903 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008904#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008905 last = NULL;
8906 next = xmlXPathNextDescendantOrSelf;
8907 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008908 case AXIS_FOLLOWING:
8909#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008910 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008911#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008912 last = NULL;
8913 next = xmlXPathNextFollowing;
8914 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008915 case AXIS_FOLLOWING_SIBLING:
8916#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008917 xmlGenericError(xmlGenericErrorContext,
8918 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008919#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008920 last = NULL;
8921 next = xmlXPathNextFollowingSibling;
8922 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008923 case AXIS_NAMESPACE:
8924#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008925 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008926#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008927 first = NULL;
8928 last = NULL;
8929 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00008930 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008931 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008932 case AXIS_PARENT:
8933#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008934 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008935#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008936 first = NULL;
8937 next = xmlXPathNextParent;
8938 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008939 case AXIS_PRECEDING:
8940#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008941 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008942#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008943 first = NULL;
8944 next = xmlXPathNextPrecedingInternal;
8945 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008946 case AXIS_PRECEDING_SIBLING:
8947#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008948 xmlGenericError(xmlGenericErrorContext,
8949 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008950#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008951 first = NULL;
8952 next = xmlXPathNextPrecedingSibling;
8953 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008954 case AXIS_SELF:
8955#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008956 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008957#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008958 first = NULL;
8959 last = NULL;
8960 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00008961 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008962 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008963 }
8964 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008965 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008966
8967 nodelist = obj->nodesetval;
8968 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008969 xmlXPathFreeObject(obj);
8970 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8971 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008972 }
8973 addNode = xmlXPathNodeSetAddUnique;
8974 ret = NULL;
8975#ifdef DEBUG_STEP
8976 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008977 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008978 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008979 case NODE_TEST_NONE:
8980 xmlGenericError(xmlGenericErrorContext,
8981 " searching for none !!!\n");
8982 break;
8983 case NODE_TEST_TYPE:
8984 xmlGenericError(xmlGenericErrorContext,
8985 " searching for type %d\n", type);
8986 break;
8987 case NODE_TEST_PI:
8988 xmlGenericError(xmlGenericErrorContext,
8989 " searching for PI !!!\n");
8990 break;
8991 case NODE_TEST_ALL:
8992 xmlGenericError(xmlGenericErrorContext,
8993 " searching for *\n");
8994 break;
8995 case NODE_TEST_NS:
8996 xmlGenericError(xmlGenericErrorContext,
8997 " searching for namespace %s\n",
8998 prefix);
8999 break;
9000 case NODE_TEST_NAME:
9001 xmlGenericError(xmlGenericErrorContext,
9002 " searching for name %s\n", name);
9003 if (prefix != NULL)
9004 xmlGenericError(xmlGenericErrorContext,
9005 " with namespace %s\n", prefix);
9006 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009007 }
9008 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9009#endif
9010 /*
9011 * 2.3 Node Tests
9012 * - For the attribute axis, the principal node type is attribute.
9013 * - For the namespace axis, the principal node type is namespace.
9014 * - For other axes, the principal node type is element.
9015 *
9016 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009017 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009018 * select all element children of the context node
9019 */
9020 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009021 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009022 ctxt->context->node = nodelist->nodeTab[i];
9023
Daniel Veillardf06307e2001-07-03 10:35:50 +00009024 cur = NULL;
9025 list = xmlXPathNodeSetCreate(NULL);
9026 do {
9027 cur = next(ctxt, cur);
9028 if (cur == NULL)
9029 break;
9030 if ((first != NULL) && (*first == cur))
9031 break;
9032 if (((t % 256) == 0) &&
9033 (first != NULL) && (*first != NULL) &&
9034 (xmlXPathCmpNodes(*first, cur) >= 0))
9035 break;
9036 if ((last != NULL) && (*last == cur))
9037 break;
9038 if (((t % 256) == 0) &&
9039 (last != NULL) && (*last != NULL) &&
9040 (xmlXPathCmpNodes(cur, *last) >= 0))
9041 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009042 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009043#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009044 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
9045#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009046 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009047 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009048 ctxt->context->node = tmp;
9049 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009050 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009051 if ((cur->type == type) ||
9052 ((type == NODE_TYPE_NODE) &&
9053 ((cur->type == XML_DOCUMENT_NODE) ||
9054 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9055 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00009056 (cur->type == XML_NAMESPACE_DECL) ||
9057 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00009058 (cur->type == XML_PI_NODE) ||
9059 (cur->type == XML_COMMENT_NODE) ||
9060 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00009061 (cur->type == XML_TEXT_NODE))) ||
9062 ((type == NODE_TYPE_TEXT) &&
9063 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009064#ifdef DEBUG_STEP
9065 n++;
9066#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009067 addNode(list, cur);
9068 }
9069 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009070 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009071 if (cur->type == XML_PI_NODE) {
9072 if ((name != NULL) &&
9073 (!xmlStrEqual(name, cur->name)))
9074 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009075#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009076 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009077#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009078 addNode(list, cur);
9079 }
9080 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009081 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009082 if (axis == AXIS_ATTRIBUTE) {
9083 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009084#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009085 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009086#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009087 addNode(list, cur);
9088 }
9089 } else if (axis == AXIS_NAMESPACE) {
9090 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009091#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009092 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009093#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009094 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9095 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009096 }
9097 } else {
9098 if (cur->type == XML_ELEMENT_NODE) {
9099 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009100#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009101 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009102#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009103 addNode(list, cur);
9104 } else if ((cur->ns != NULL) &&
9105 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009106#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009107 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009108#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009109 addNode(list, cur);
9110 }
9111 }
9112 }
9113 break;
9114 case NODE_TEST_NS:{
9115 TODO;
9116 break;
9117 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009118 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009119 switch (cur->type) {
9120 case XML_ELEMENT_NODE:
9121 if (xmlStrEqual(name, cur->name)) {
9122 if (prefix == NULL) {
9123 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009124#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009125 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009126#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009127 addNode(list, cur);
9128 }
9129 } else {
9130 if ((cur->ns != NULL) &&
9131 (xmlStrEqual(URI,
9132 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009133#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009134 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009135#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009136 addNode(list, cur);
9137 }
9138 }
9139 }
9140 break;
9141 case XML_ATTRIBUTE_NODE:{
9142 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009143
Daniel Veillardf06307e2001-07-03 10:35:50 +00009144 if (xmlStrEqual(name, attr->name)) {
9145 if (prefix == NULL) {
9146 if ((attr->ns == NULL) ||
9147 (attr->ns->prefix == NULL)) {
9148#ifdef DEBUG_STEP
9149 n++;
9150#endif
9151 addNode(list,
9152 (xmlNodePtr) attr);
9153 }
9154 } else {
9155 if ((attr->ns != NULL) &&
9156 (xmlStrEqual(URI,
9157 attr->ns->
9158 href))) {
9159#ifdef DEBUG_STEP
9160 n++;
9161#endif
9162 addNode(list,
9163 (xmlNodePtr) attr);
9164 }
9165 }
9166 }
9167 break;
9168 }
9169 case XML_NAMESPACE_DECL:
9170 if (cur->type == XML_NAMESPACE_DECL) {
9171 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009172
Daniel Veillardf06307e2001-07-03 10:35:50 +00009173 if ((ns->prefix != NULL) && (name != NULL)
9174 && (xmlStrEqual(ns->prefix, name))) {
9175#ifdef DEBUG_STEP
9176 n++;
9177#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009178 xmlXPathNodeSetAddNs(list,
9179 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009180 }
9181 }
9182 break;
9183 default:
9184 break;
9185 }
9186 break;
9187 break;
9188 }
9189 } while (cur != NULL);
9190
9191 /*
9192 * If there is some predicate filtering do it now
9193 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009194 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009195 xmlXPathObjectPtr obj2;
9196
9197 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9198 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9199 CHECK_TYPE0(XPATH_NODESET);
9200 obj2 = valuePop(ctxt);
9201 list = obj2->nodesetval;
9202 obj2->nodesetval = NULL;
9203 xmlXPathFreeObject(obj2);
9204 }
9205 if (ret == NULL) {
9206 ret = list;
9207 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009208 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009209 xmlXPathFreeNodeSet(list);
9210 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009211 }
9212 ctxt->context->node = tmp;
9213#ifdef DEBUG_STEP
9214 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009215 "\nExamined %d nodes, found %d nodes at that step\n",
9216 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009217#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009218 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009219 if ((obj->boolval) && (obj->user != NULL)) {
9220 ctxt->value->boolval = 1;
9221 ctxt->value->user = obj->user;
9222 obj->user = NULL;
9223 obj->boolval = 0;
9224 }
9225 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009226 return(t);
9227}
9228
9229/**
9230 * xmlXPathNodeCollectAndTestNth:
9231 * @ctxt: the XPath Parser context
9232 * @op: the XPath precompiled step operation
9233 * @indx: the index to collect
9234 * @first: pointer to the first element in document order
9235 * @last: pointer to the last element in document order
9236 *
9237 * This is the function implementing a step: based on the current list
9238 * of nodes, it builds up a new list, looking at all nodes under that
9239 * axis and selecting them it also do the predicate filtering
9240 *
9241 * Pushes the new NodeSet resulting from the search.
9242 * Returns the number of node traversed
9243 */
9244static int
9245xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9246 xmlXPathStepOpPtr op, int indx,
9247 xmlNodePtr * first, xmlNodePtr * last)
9248{
9249 xmlXPathAxisVal axis = op->value;
9250 xmlXPathTestVal test = op->value2;
9251 xmlXPathTypeVal type = op->value3;
9252 const xmlChar *prefix = op->value4;
9253 const xmlChar *name = op->value5;
9254 const xmlChar *URI = NULL;
9255 int n = 0, t = 0;
9256
9257 int i;
9258 xmlNodeSetPtr list;
9259 xmlXPathTraversalFunction next = NULL;
9260 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9261 xmlNodePtr cur = NULL;
9262 xmlXPathObjectPtr obj;
9263 xmlNodeSetPtr nodelist;
9264 xmlNodePtr tmp;
9265
9266 CHECK_TYPE0(XPATH_NODESET);
9267 obj = valuePop(ctxt);
9268 addNode = xmlXPathNodeSetAdd;
9269 if (prefix != NULL) {
9270 URI = xmlXPathNsLookup(ctxt->context, prefix);
9271 if (URI == NULL)
9272 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9273 }
9274#ifdef DEBUG_STEP_NTH
9275 xmlGenericError(xmlGenericErrorContext, "new step : ");
9276 if (first != NULL) {
9277 if (*first != NULL)
9278 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9279 (*first)->name);
9280 else
9281 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9282 }
9283 if (last != NULL) {
9284 if (*last != NULL)
9285 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9286 (*last)->name);
9287 else
9288 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9289 }
9290#endif
9291 switch (axis) {
9292 case AXIS_ANCESTOR:
9293#ifdef DEBUG_STEP_NTH
9294 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9295#endif
9296 first = NULL;
9297 next = xmlXPathNextAncestor;
9298 break;
9299 case AXIS_ANCESTOR_OR_SELF:
9300#ifdef DEBUG_STEP_NTH
9301 xmlGenericError(xmlGenericErrorContext,
9302 "axis 'ancestors-or-self' ");
9303#endif
9304 first = NULL;
9305 next = xmlXPathNextAncestorOrSelf;
9306 break;
9307 case AXIS_ATTRIBUTE:
9308#ifdef DEBUG_STEP_NTH
9309 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9310#endif
9311 first = NULL;
9312 last = NULL;
9313 next = xmlXPathNextAttribute;
9314 break;
9315 case AXIS_CHILD:
9316#ifdef DEBUG_STEP_NTH
9317 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9318#endif
9319 last = NULL;
9320 next = xmlXPathNextChild;
9321 break;
9322 case AXIS_DESCENDANT:
9323#ifdef DEBUG_STEP_NTH
9324 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9325#endif
9326 last = NULL;
9327 next = xmlXPathNextDescendant;
9328 break;
9329 case AXIS_DESCENDANT_OR_SELF:
9330#ifdef DEBUG_STEP_NTH
9331 xmlGenericError(xmlGenericErrorContext,
9332 "axis 'descendant-or-self' ");
9333#endif
9334 last = NULL;
9335 next = xmlXPathNextDescendantOrSelf;
9336 break;
9337 case AXIS_FOLLOWING:
9338#ifdef DEBUG_STEP_NTH
9339 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9340#endif
9341 last = NULL;
9342 next = xmlXPathNextFollowing;
9343 break;
9344 case AXIS_FOLLOWING_SIBLING:
9345#ifdef DEBUG_STEP_NTH
9346 xmlGenericError(xmlGenericErrorContext,
9347 "axis 'following-siblings' ");
9348#endif
9349 last = NULL;
9350 next = xmlXPathNextFollowingSibling;
9351 break;
9352 case AXIS_NAMESPACE:
9353#ifdef DEBUG_STEP_NTH
9354 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9355#endif
9356 last = NULL;
9357 first = NULL;
9358 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9359 break;
9360 case AXIS_PARENT:
9361#ifdef DEBUG_STEP_NTH
9362 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9363#endif
9364 first = NULL;
9365 next = xmlXPathNextParent;
9366 break;
9367 case AXIS_PRECEDING:
9368#ifdef DEBUG_STEP_NTH
9369 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9370#endif
9371 first = NULL;
9372 next = xmlXPathNextPrecedingInternal;
9373 break;
9374 case AXIS_PRECEDING_SIBLING:
9375#ifdef DEBUG_STEP_NTH
9376 xmlGenericError(xmlGenericErrorContext,
9377 "axis 'preceding-sibling' ");
9378#endif
9379 first = NULL;
9380 next = xmlXPathNextPrecedingSibling;
9381 break;
9382 case AXIS_SELF:
9383#ifdef DEBUG_STEP_NTH
9384 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9385#endif
9386 first = NULL;
9387 last = NULL;
9388 next = xmlXPathNextSelf;
9389 break;
9390 }
9391 if (next == NULL)
9392 return(0);
9393
9394 nodelist = obj->nodesetval;
9395 if (nodelist == NULL) {
9396 xmlXPathFreeObject(obj);
9397 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9398 return(0);
9399 }
9400 addNode = xmlXPathNodeSetAddUnique;
9401#ifdef DEBUG_STEP_NTH
9402 xmlGenericError(xmlGenericErrorContext,
9403 " context contains %d nodes\n", nodelist->nodeNr);
9404 switch (test) {
9405 case NODE_TEST_NONE:
9406 xmlGenericError(xmlGenericErrorContext,
9407 " searching for none !!!\n");
9408 break;
9409 case NODE_TEST_TYPE:
9410 xmlGenericError(xmlGenericErrorContext,
9411 " searching for type %d\n", type);
9412 break;
9413 case NODE_TEST_PI:
9414 xmlGenericError(xmlGenericErrorContext,
9415 " searching for PI !!!\n");
9416 break;
9417 case NODE_TEST_ALL:
9418 xmlGenericError(xmlGenericErrorContext,
9419 " searching for *\n");
9420 break;
9421 case NODE_TEST_NS:
9422 xmlGenericError(xmlGenericErrorContext,
9423 " searching for namespace %s\n",
9424 prefix);
9425 break;
9426 case NODE_TEST_NAME:
9427 xmlGenericError(xmlGenericErrorContext,
9428 " searching for name %s\n", name);
9429 if (prefix != NULL)
9430 xmlGenericError(xmlGenericErrorContext,
9431 " with namespace %s\n", prefix);
9432 break;
9433 }
9434 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9435#endif
9436 /*
9437 * 2.3 Node Tests
9438 * - For the attribute axis, the principal node type is attribute.
9439 * - For the namespace axis, the principal node type is namespace.
9440 * - For other axes, the principal node type is element.
9441 *
9442 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009443 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009444 * select all element children of the context node
9445 */
9446 tmp = ctxt->context->node;
9447 list = xmlXPathNodeSetCreate(NULL);
9448 for (i = 0; i < nodelist->nodeNr; i++) {
9449 ctxt->context->node = nodelist->nodeTab[i];
9450
9451 cur = NULL;
9452 n = 0;
9453 do {
9454 cur = next(ctxt, cur);
9455 if (cur == NULL)
9456 break;
9457 if ((first != NULL) && (*first == cur))
9458 break;
9459 if (((t % 256) == 0) &&
9460 (first != NULL) && (*first != NULL) &&
9461 (xmlXPathCmpNodes(*first, cur) >= 0))
9462 break;
9463 if ((last != NULL) && (*last == cur))
9464 break;
9465 if (((t % 256) == 0) &&
9466 (last != NULL) && (*last != NULL) &&
9467 (xmlXPathCmpNodes(cur, *last) >= 0))
9468 break;
9469 t++;
9470 switch (test) {
9471 case NODE_TEST_NONE:
9472 ctxt->context->node = tmp;
9473 STRANGE return(0);
9474 case NODE_TEST_TYPE:
9475 if ((cur->type == type) ||
9476 ((type == NODE_TYPE_NODE) &&
9477 ((cur->type == XML_DOCUMENT_NODE) ||
9478 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9479 (cur->type == XML_ELEMENT_NODE) ||
9480 (cur->type == XML_PI_NODE) ||
9481 (cur->type == XML_COMMENT_NODE) ||
9482 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +00009483 (cur->type == XML_TEXT_NODE))) ||
9484 ((type == NODE_TYPE_TEXT) &&
9485 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009486 n++;
9487 if (n == indx)
9488 addNode(list, cur);
9489 }
9490 break;
9491 case NODE_TEST_PI:
9492 if (cur->type == XML_PI_NODE) {
9493 if ((name != NULL) &&
9494 (!xmlStrEqual(name, cur->name)))
9495 break;
9496 n++;
9497 if (n == indx)
9498 addNode(list, cur);
9499 }
9500 break;
9501 case NODE_TEST_ALL:
9502 if (axis == AXIS_ATTRIBUTE) {
9503 if (cur->type == XML_ATTRIBUTE_NODE) {
9504 n++;
9505 if (n == indx)
9506 addNode(list, cur);
9507 }
9508 } else if (axis == AXIS_NAMESPACE) {
9509 if (cur->type == XML_NAMESPACE_DECL) {
9510 n++;
9511 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009512 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9513 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009514 }
9515 } else {
9516 if (cur->type == XML_ELEMENT_NODE) {
9517 if (prefix == NULL) {
9518 n++;
9519 if (n == indx)
9520 addNode(list, cur);
9521 } else if ((cur->ns != NULL) &&
9522 (xmlStrEqual(URI, cur->ns->href))) {
9523 n++;
9524 if (n == indx)
9525 addNode(list, cur);
9526 }
9527 }
9528 }
9529 break;
9530 case NODE_TEST_NS:{
9531 TODO;
9532 break;
9533 }
9534 case NODE_TEST_NAME:
9535 switch (cur->type) {
9536 case XML_ELEMENT_NODE:
9537 if (xmlStrEqual(name, cur->name)) {
9538 if (prefix == NULL) {
9539 if (cur->ns == NULL) {
9540 n++;
9541 if (n == indx)
9542 addNode(list, cur);
9543 }
9544 } else {
9545 if ((cur->ns != NULL) &&
9546 (xmlStrEqual(URI,
9547 cur->ns->href))) {
9548 n++;
9549 if (n == indx)
9550 addNode(list, cur);
9551 }
9552 }
9553 }
9554 break;
9555 case XML_ATTRIBUTE_NODE:{
9556 xmlAttrPtr attr = (xmlAttrPtr) cur;
9557
9558 if (xmlStrEqual(name, attr->name)) {
9559 if (prefix == NULL) {
9560 if ((attr->ns == NULL) ||
9561 (attr->ns->prefix == NULL)) {
9562 n++;
9563 if (n == indx)
9564 addNode(list, cur);
9565 }
9566 } else {
9567 if ((attr->ns != NULL) &&
9568 (xmlStrEqual(URI,
9569 attr->ns->
9570 href))) {
9571 n++;
9572 if (n == indx)
9573 addNode(list, cur);
9574 }
9575 }
9576 }
9577 break;
9578 }
9579 case XML_NAMESPACE_DECL:
9580 if (cur->type == XML_NAMESPACE_DECL) {
9581 xmlNsPtr ns = (xmlNsPtr) cur;
9582
9583 if ((ns->prefix != NULL) && (name != NULL)
9584 && (xmlStrEqual(ns->prefix, name))) {
9585 n++;
9586 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009587 xmlXPathNodeSetAddNs(list,
9588 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009589 }
9590 }
9591 break;
9592 default:
9593 break;
9594 }
9595 break;
9596 break;
9597 }
9598 } while (n < indx);
9599 }
9600 ctxt->context->node = tmp;
9601#ifdef DEBUG_STEP_NTH
9602 xmlGenericError(xmlGenericErrorContext,
9603 "\nExamined %d nodes, found %d nodes at that step\n",
9604 t, list->nodeNr);
9605#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009606 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009607 if ((obj->boolval) && (obj->user != NULL)) {
9608 ctxt->value->boolval = 1;
9609 ctxt->value->user = obj->user;
9610 obj->user = NULL;
9611 obj->boolval = 0;
9612 }
9613 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009614 return(t);
9615}
9616
9617/**
9618 * xmlXPathCompOpEvalFirst:
9619 * @ctxt: the XPath parser context with the compiled expression
9620 * @op: an XPath compiled operation
9621 * @first: the first elem found so far
9622 *
9623 * Evaluate the Precompiled XPath operation searching only the first
9624 * element in document order
9625 *
9626 * Returns the number of examined objects.
9627 */
9628static int
9629xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9630 xmlXPathStepOpPtr op, xmlNodePtr * first)
9631{
9632 int total = 0, cur;
9633 xmlXPathCompExprPtr comp;
9634 xmlXPathObjectPtr arg1, arg2;
9635
Daniel Veillard556c6682001-10-06 09:59:51 +00009636 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009637 comp = ctxt->comp;
9638 switch (op->op) {
9639 case XPATH_OP_END:
9640 return (0);
9641 case XPATH_OP_UNION:
9642 total =
9643 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9644 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009645 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009646 if ((ctxt->value != NULL)
9647 && (ctxt->value->type == XPATH_NODESET)
9648 && (ctxt->value->nodesetval != NULL)
9649 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9650 /*
9651 * limit tree traversing to first node in the result
9652 */
9653 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9654 *first = ctxt->value->nodesetval->nodeTab[0];
9655 }
9656 cur =
9657 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9658 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009659 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009660 CHECK_TYPE0(XPATH_NODESET);
9661 arg2 = valuePop(ctxt);
9662
9663 CHECK_TYPE0(XPATH_NODESET);
9664 arg1 = valuePop(ctxt);
9665
9666 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9667 arg2->nodesetval);
9668 valuePush(ctxt, arg1);
9669 xmlXPathFreeObject(arg2);
9670 /* optimizer */
9671 if (total > cur)
9672 xmlXPathCompSwap(op);
9673 return (total + cur);
9674 case XPATH_OP_ROOT:
9675 xmlXPathRoot(ctxt);
9676 return (0);
9677 case XPATH_OP_NODE:
9678 if (op->ch1 != -1)
9679 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009680 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009681 if (op->ch2 != -1)
9682 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009683 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009684 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9685 return (total);
9686 case XPATH_OP_RESET:
9687 if (op->ch1 != -1)
9688 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009689 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009690 if (op->ch2 != -1)
9691 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009692 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009693 ctxt->context->node = NULL;
9694 return (total);
9695 case XPATH_OP_COLLECT:{
9696 if (op->ch1 == -1)
9697 return (total);
9698
9699 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009700 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009701
9702 /*
9703 * Optimization for [n] selection where n is a number
9704 */
9705 if ((op->ch2 != -1) &&
9706 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9707 (comp->steps[op->ch2].ch1 == -1) &&
9708 (comp->steps[op->ch2].ch2 != -1) &&
9709 (comp->steps[comp->steps[op->ch2].ch2].op ==
9710 XPATH_OP_VALUE)) {
9711 xmlXPathObjectPtr val;
9712
9713 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9714 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9715 int indx = (int) val->floatval;
9716
9717 if (val->floatval == (float) indx) {
9718 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9719 first, NULL);
9720 return (total);
9721 }
9722 }
9723 }
9724 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9725 return (total);
9726 }
9727 case XPATH_OP_VALUE:
9728 valuePush(ctxt,
9729 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9730 return (0);
9731 case XPATH_OP_SORT:
9732 if (op->ch1 != -1)
9733 total +=
9734 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9735 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009736 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009737 if ((ctxt->value != NULL)
9738 && (ctxt->value->type == XPATH_NODESET)
9739 && (ctxt->value->nodesetval != NULL))
9740 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9741 return (total);
9742 default:
9743 return (xmlXPathCompOpEval(ctxt, op));
9744 }
9745}
9746
9747/**
9748 * xmlXPathCompOpEvalLast:
9749 * @ctxt: the XPath parser context with the compiled expression
9750 * @op: an XPath compiled operation
9751 * @last: the last elem found so far
9752 *
9753 * Evaluate the Precompiled XPath operation searching only the last
9754 * element in document order
9755 *
9756 * Returns the number of node traversed
9757 */
9758static int
9759xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9760 xmlNodePtr * last)
9761{
9762 int total = 0, cur;
9763 xmlXPathCompExprPtr comp;
9764 xmlXPathObjectPtr arg1, arg2;
9765
Daniel Veillard556c6682001-10-06 09:59:51 +00009766 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009767 comp = ctxt->comp;
9768 switch (op->op) {
9769 case XPATH_OP_END:
9770 return (0);
9771 case XPATH_OP_UNION:
9772 total =
9773 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009774 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009775 if ((ctxt->value != NULL)
9776 && (ctxt->value->type == XPATH_NODESET)
9777 && (ctxt->value->nodesetval != NULL)
9778 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9779 /*
9780 * limit tree traversing to first node in the result
9781 */
9782 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9783 *last =
9784 ctxt->value->nodesetval->nodeTab[ctxt->value->
9785 nodesetval->nodeNr -
9786 1];
9787 }
9788 cur =
9789 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009790 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009791 if ((ctxt->value != NULL)
9792 && (ctxt->value->type == XPATH_NODESET)
9793 && (ctxt->value->nodesetval != NULL)
9794 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9795 }
9796 CHECK_TYPE0(XPATH_NODESET);
9797 arg2 = valuePop(ctxt);
9798
9799 CHECK_TYPE0(XPATH_NODESET);
9800 arg1 = valuePop(ctxt);
9801
9802 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9803 arg2->nodesetval);
9804 valuePush(ctxt, arg1);
9805 xmlXPathFreeObject(arg2);
9806 /* optimizer */
9807 if (total > cur)
9808 xmlXPathCompSwap(op);
9809 return (total + cur);
9810 case XPATH_OP_ROOT:
9811 xmlXPathRoot(ctxt);
9812 return (0);
9813 case XPATH_OP_NODE:
9814 if (op->ch1 != -1)
9815 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009816 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009817 if (op->ch2 != -1)
9818 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009819 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009820 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9821 return (total);
9822 case XPATH_OP_RESET:
9823 if (op->ch1 != -1)
9824 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009825 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009826 if (op->ch2 != -1)
9827 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009828 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009829 ctxt->context->node = NULL;
9830 return (total);
9831 case XPATH_OP_COLLECT:{
9832 if (op->ch1 == -1)
9833 return (0);
9834
9835 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009836 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009837
9838 /*
9839 * Optimization for [n] selection where n is a number
9840 */
9841 if ((op->ch2 != -1) &&
9842 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9843 (comp->steps[op->ch2].ch1 == -1) &&
9844 (comp->steps[op->ch2].ch2 != -1) &&
9845 (comp->steps[comp->steps[op->ch2].ch2].op ==
9846 XPATH_OP_VALUE)) {
9847 xmlXPathObjectPtr val;
9848
9849 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9850 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9851 int indx = (int) val->floatval;
9852
9853 if (val->floatval == (float) indx) {
9854 total +=
9855 xmlXPathNodeCollectAndTestNth(ctxt, op,
9856 indx, NULL,
9857 last);
9858 return (total);
9859 }
9860 }
9861 }
9862 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9863 return (total);
9864 }
9865 case XPATH_OP_VALUE:
9866 valuePush(ctxt,
9867 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9868 return (0);
9869 case XPATH_OP_SORT:
9870 if (op->ch1 != -1)
9871 total +=
9872 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9873 last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009874 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009875 if ((ctxt->value != NULL)
9876 && (ctxt->value->type == XPATH_NODESET)
9877 && (ctxt->value->nodesetval != NULL))
9878 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9879 return (total);
9880 default:
9881 return (xmlXPathCompOpEval(ctxt, op));
9882 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009883}
9884
Owen Taylor3473f882001-02-23 17:55:21 +00009885/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009886 * xmlXPathCompOpEval:
9887 * @ctxt: the XPath parser context with the compiled expression
9888 * @op: an XPath compiled operation
9889 *
9890 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009891 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009892 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009893static int
9894xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9895{
9896 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009897 int equal, ret;
9898 xmlXPathCompExprPtr comp;
9899 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009900 xmlNodePtr bak;
9901 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +00009902 int pp;
William M. Brack692092b2002-06-28 15:01:24 +00009903 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009904
Daniel Veillard556c6682001-10-06 09:59:51 +00009905 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009906 comp = ctxt->comp;
9907 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009908 case XPATH_OP_END:
9909 return (0);
9910 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009911 bakd = ctxt->context->doc;
9912 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009913 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009914 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009915 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009916 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009917 xmlXPathBooleanFunction(ctxt, 1);
9918 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9919 return (total);
9920 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009921 ctxt->context->doc = bakd;
9922 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009923 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009924 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009925 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009926 if (ctxt->error) {
9927 xmlXPathFreeObject(arg2);
9928 return(0);
9929 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009930 xmlXPathBooleanFunction(ctxt, 1);
9931 arg1 = valuePop(ctxt);
9932 arg1->boolval &= arg2->boolval;
9933 valuePush(ctxt, arg1);
9934 xmlXPathFreeObject(arg2);
9935 return (total);
9936 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009937 bakd = ctxt->context->doc;
9938 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009939 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009940 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009941 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009942 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009943 xmlXPathBooleanFunction(ctxt, 1);
9944 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9945 return (total);
9946 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009947 ctxt->context->doc = bakd;
9948 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009949 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009950 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009951 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009952 if (ctxt->error) {
9953 xmlXPathFreeObject(arg2);
9954 return(0);
9955 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009956 xmlXPathBooleanFunction(ctxt, 1);
9957 arg1 = valuePop(ctxt);
9958 arg1->boolval |= arg2->boolval;
9959 valuePush(ctxt, arg1);
9960 xmlXPathFreeObject(arg2);
9961 return (total);
9962 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009963 bakd = ctxt->context->doc;
9964 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009965 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009966 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009967 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009968 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009969 ctxt->context->doc = bakd;
9970 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009971 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009972 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009973 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009974 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +00009975 if (op->value)
9976 equal = xmlXPathEqualValues(ctxt);
9977 else
9978 equal = xmlXPathNotEqualValues(ctxt);
9979 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +00009980 return (total);
9981 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009982 bakd = ctxt->context->doc;
9983 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009984 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009985 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009986 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009987 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009988 ctxt->context->doc = bakd;
9989 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009990 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009991 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009992 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009993 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009994 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
9995 valuePush(ctxt, xmlXPathNewBoolean(ret));
9996 return (total);
9997 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009998 bakd = ctxt->context->doc;
9999 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010000 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010001 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010002 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010003 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010004 if (op->ch2 != -1) {
10005 ctxt->context->doc = bakd;
10006 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010007 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010008 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010009 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010010 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010011 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010012 if (op->value == 0)
10013 xmlXPathSubValues(ctxt);
10014 else if (op->value == 1)
10015 xmlXPathAddValues(ctxt);
10016 else if (op->value == 2)
10017 xmlXPathValueFlipSign(ctxt);
10018 else if (op->value == 3) {
10019 CAST_TO_NUMBER;
10020 CHECK_TYPE0(XPATH_NUMBER);
10021 }
10022 return (total);
10023 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010024 bakd = ctxt->context->doc;
10025 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010026 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010027 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010028 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010029 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010030 ctxt->context->doc = bakd;
10031 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010032 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010033 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010034 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010035 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010036 if (op->value == 0)
10037 xmlXPathMultValues(ctxt);
10038 else if (op->value == 1)
10039 xmlXPathDivValues(ctxt);
10040 else if (op->value == 2)
10041 xmlXPathModValues(ctxt);
10042 return (total);
10043 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010044 bakd = ctxt->context->doc;
10045 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010046 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010047 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010048 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010049 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010050 ctxt->context->doc = bakd;
10051 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010052 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010053 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010054 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010055 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010056 CHECK_TYPE0(XPATH_NODESET);
10057 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010058
Daniel Veillardf06307e2001-07-03 10:35:50 +000010059 CHECK_TYPE0(XPATH_NODESET);
10060 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010061
Daniel Veillardf06307e2001-07-03 10:35:50 +000010062 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10063 arg2->nodesetval);
10064 valuePush(ctxt, arg1);
10065 xmlXPathFreeObject(arg2);
10066 return (total);
10067 case XPATH_OP_ROOT:
10068 xmlXPathRoot(ctxt);
10069 return (total);
10070 case XPATH_OP_NODE:
10071 if (op->ch1 != -1)
10072 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010073 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010074 if (op->ch2 != -1)
10075 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010076 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010077 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10078 return (total);
10079 case XPATH_OP_RESET:
10080 if (op->ch1 != -1)
10081 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010082 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010083 if (op->ch2 != -1)
10084 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010085 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010086 ctxt->context->node = NULL;
10087 return (total);
10088 case XPATH_OP_COLLECT:{
10089 if (op->ch1 == -1)
10090 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010091
Daniel Veillardf06307e2001-07-03 10:35:50 +000010092 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010093 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010094
Daniel Veillardf06307e2001-07-03 10:35:50 +000010095 /*
10096 * Optimization for [n] selection where n is a number
10097 */
10098 if ((op->ch2 != -1) &&
10099 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10100 (comp->steps[op->ch2].ch1 == -1) &&
10101 (comp->steps[op->ch2].ch2 != -1) &&
10102 (comp->steps[comp->steps[op->ch2].ch2].op ==
10103 XPATH_OP_VALUE)) {
10104 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +000010105
Daniel Veillardf06307e2001-07-03 10:35:50 +000010106 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10107 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10108 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010109
Daniel Veillardf06307e2001-07-03 10:35:50 +000010110 if (val->floatval == (float) indx) {
10111 total +=
10112 xmlXPathNodeCollectAndTestNth(ctxt, op,
10113 indx, NULL,
10114 NULL);
10115 return (total);
10116 }
10117 }
10118 }
10119 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
10120 return (total);
10121 }
10122 case XPATH_OP_VALUE:
10123 valuePush(ctxt,
10124 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10125 return (total);
10126 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000010127 xmlXPathObjectPtr val;
10128
Daniel Veillardf06307e2001-07-03 10:35:50 +000010129 if (op->ch1 != -1)
10130 total +=
10131 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010132 if (op->value5 == NULL) {
10133 val = xmlXPathVariableLookup(ctxt->context, op->value4);
10134 if (val == NULL) {
10135 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10136 return(0);
10137 }
10138 valuePush(ctxt, val);
10139 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010140 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010141
Daniel Veillardf06307e2001-07-03 10:35:50 +000010142 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10143 if (URI == NULL) {
10144 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010145 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010146 op->value4, op->value5);
10147 return (total);
10148 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010149 val = xmlXPathVariableLookupNS(ctxt->context,
10150 op->value4, URI);
10151 if (val == NULL) {
10152 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10153 return(0);
10154 }
10155 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010156 }
10157 return (total);
10158 }
10159 case XPATH_OP_FUNCTION:{
10160 xmlXPathFunction func;
10161 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000010162 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010163
10164 if (op->ch1 != -1)
10165 total +=
10166 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010167 if (ctxt->valueNr < op->value) {
10168 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010169 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010170 ctxt->error = XPATH_INVALID_OPERAND;
10171 return (total);
10172 }
10173 for (i = 0; i < op->value; i++)
10174 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10175 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010176 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010177 ctxt->error = XPATH_INVALID_OPERAND;
10178 return (total);
10179 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010180 if (op->cache != NULL)
10181 func = (xmlXPathFunction) op->cache;
10182 else {
10183 const xmlChar *URI = NULL;
10184
10185 if (op->value5 == NULL)
10186 func =
10187 xmlXPathFunctionLookup(ctxt->context,
10188 op->value4);
10189 else {
10190 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10191 if (URI == NULL) {
10192 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010193 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010194 op->value4, op->value5);
10195 return (total);
10196 }
10197 func = xmlXPathFunctionLookupNS(ctxt->context,
10198 op->value4, URI);
10199 }
10200 if (func == NULL) {
10201 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010202 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010203 op->value4);
10204 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010205 }
10206 op->cache = (void *) func;
10207 op->cacheURI = (void *) URI;
10208 }
10209 oldFunc = ctxt->context->function;
10210 oldFuncURI = ctxt->context->functionURI;
10211 ctxt->context->function = op->value4;
10212 ctxt->context->functionURI = op->cacheURI;
10213 func(ctxt, op->value);
10214 ctxt->context->function = oldFunc;
10215 ctxt->context->functionURI = oldFuncURI;
10216 return (total);
10217 }
10218 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000010219 bakd = ctxt->context->doc;
10220 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010221 if (op->ch1 != -1)
10222 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010223 ctxt->context->doc = bakd;
10224 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010225 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010226 if (op->ch2 != -1)
10227 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010228 ctxt->context->doc = bakd;
10229 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010230 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010231 return (total);
10232 case XPATH_OP_PREDICATE:
10233 case XPATH_OP_FILTER:{
10234 xmlXPathObjectPtr res;
10235 xmlXPathObjectPtr obj, tmp;
10236 xmlNodeSetPtr newset = NULL;
10237 xmlNodeSetPtr oldset;
10238 xmlNodePtr oldnode;
10239 int i;
10240
10241 /*
10242 * Optimization for ()[1] selection i.e. the first elem
10243 */
10244 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10245 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10246 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10247 xmlXPathObjectPtr val;
10248
10249 val = comp->steps[op->ch2].value4;
10250 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10251 (val->floatval == 1.0)) {
10252 xmlNodePtr first = NULL;
10253
10254 total +=
10255 xmlXPathCompOpEvalFirst(ctxt,
10256 &comp->steps[op->ch1],
10257 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010258 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010259 /*
10260 * The nodeset should be in document order,
10261 * Keep only the first value
10262 */
10263 if ((ctxt->value != NULL) &&
10264 (ctxt->value->type == XPATH_NODESET) &&
10265 (ctxt->value->nodesetval != NULL) &&
10266 (ctxt->value->nodesetval->nodeNr > 1))
10267 ctxt->value->nodesetval->nodeNr = 1;
10268 return (total);
10269 }
10270 }
10271 /*
10272 * Optimization for ()[last()] selection i.e. the last elem
10273 */
10274 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10275 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10276 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10277 int f = comp->steps[op->ch2].ch1;
10278
10279 if ((f != -1) &&
10280 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10281 (comp->steps[f].value5 == NULL) &&
10282 (comp->steps[f].value == 0) &&
10283 (comp->steps[f].value4 != NULL) &&
10284 (xmlStrEqual
10285 (comp->steps[f].value4, BAD_CAST "last"))) {
10286 xmlNodePtr last = NULL;
10287
10288 total +=
10289 xmlXPathCompOpEvalLast(ctxt,
10290 &comp->steps[op->ch1],
10291 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010292 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010293 /*
10294 * The nodeset should be in document order,
10295 * Keep only the last value
10296 */
10297 if ((ctxt->value != NULL) &&
10298 (ctxt->value->type == XPATH_NODESET) &&
10299 (ctxt->value->nodesetval != NULL) &&
10300 (ctxt->value->nodesetval->nodeTab != NULL) &&
10301 (ctxt->value->nodesetval->nodeNr > 1)) {
10302 ctxt->value->nodesetval->nodeTab[0] =
10303 ctxt->value->nodesetval->nodeTab[ctxt->
10304 value->
10305 nodesetval->
10306 nodeNr -
10307 1];
10308 ctxt->value->nodesetval->nodeNr = 1;
10309 }
10310 return (total);
10311 }
10312 }
10313
10314 if (op->ch1 != -1)
10315 total +=
10316 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010317 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010318 if (op->ch2 == -1)
10319 return (total);
10320 if (ctxt->value == NULL)
10321 return (total);
10322
10323 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010324
10325#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010326 /*
10327 * Hum are we filtering the result of an XPointer expression
10328 */
10329 if (ctxt->value->type == XPATH_LOCATIONSET) {
10330 xmlLocationSetPtr newlocset = NULL;
10331 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010332
Daniel Veillardf06307e2001-07-03 10:35:50 +000010333 /*
10334 * Extract the old locset, and then evaluate the result of the
10335 * expression for all the element in the locset. use it to grow
10336 * up a new locset.
10337 */
10338 CHECK_TYPE0(XPATH_LOCATIONSET);
10339 obj = valuePop(ctxt);
10340 oldlocset = obj->user;
10341 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010342
Daniel Veillardf06307e2001-07-03 10:35:50 +000010343 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10344 ctxt->context->contextSize = 0;
10345 ctxt->context->proximityPosition = 0;
10346 if (op->ch2 != -1)
10347 total +=
10348 xmlXPathCompOpEval(ctxt,
10349 &comp->steps[op->ch2]);
10350 res = valuePop(ctxt);
10351 if (res != NULL)
10352 xmlXPathFreeObject(res);
10353 valuePush(ctxt, obj);
10354 CHECK_ERROR0;
10355 return (total);
10356 }
10357 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010358
Daniel Veillardf06307e2001-07-03 10:35:50 +000010359 for (i = 0; i < oldlocset->locNr; i++) {
10360 /*
10361 * Run the evaluation with a node list made of a
10362 * single item in the nodelocset.
10363 */
10364 ctxt->context->node = oldlocset->locTab[i]->user;
10365 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10366 valuePush(ctxt, tmp);
10367 ctxt->context->contextSize = oldlocset->locNr;
10368 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010369
Daniel Veillardf06307e2001-07-03 10:35:50 +000010370 if (op->ch2 != -1)
10371 total +=
10372 xmlXPathCompOpEval(ctxt,
10373 &comp->steps[op->ch2]);
10374 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010375
Daniel Veillardf06307e2001-07-03 10:35:50 +000010376 /*
10377 * The result of the evaluation need to be tested to
10378 * decided whether the filter succeeded or not
10379 */
10380 res = valuePop(ctxt);
10381 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10382 xmlXPtrLocationSetAdd(newlocset,
10383 xmlXPathObjectCopy
10384 (oldlocset->locTab[i]));
10385 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010386
Daniel Veillardf06307e2001-07-03 10:35:50 +000010387 /*
10388 * Cleanup
10389 */
10390 if (res != NULL)
10391 xmlXPathFreeObject(res);
10392 if (ctxt->value == tmp) {
10393 res = valuePop(ctxt);
10394 xmlXPathFreeObject(res);
10395 }
10396
10397 ctxt->context->node = NULL;
10398 }
10399
10400 /*
10401 * The result is used as the new evaluation locset.
10402 */
10403 xmlXPathFreeObject(obj);
10404 ctxt->context->node = NULL;
10405 ctxt->context->contextSize = -1;
10406 ctxt->context->proximityPosition = -1;
10407 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10408 ctxt->context->node = oldnode;
10409 return (total);
10410 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010411#endif /* LIBXML_XPTR_ENABLED */
10412
Daniel Veillardf06307e2001-07-03 10:35:50 +000010413 /*
10414 * Extract the old set, and then evaluate the result of the
10415 * expression for all the element in the set. use it to grow
10416 * up a new set.
10417 */
10418 CHECK_TYPE0(XPATH_NODESET);
10419 obj = valuePop(ctxt);
10420 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010421
Daniel Veillardf06307e2001-07-03 10:35:50 +000010422 oldnode = ctxt->context->node;
10423 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010424
Daniel Veillardf06307e2001-07-03 10:35:50 +000010425 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10426 ctxt->context->contextSize = 0;
10427 ctxt->context->proximityPosition = 0;
10428 if (op->ch2 != -1)
10429 total +=
10430 xmlXPathCompOpEval(ctxt,
10431 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010432 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010433 res = valuePop(ctxt);
10434 if (res != NULL)
10435 xmlXPathFreeObject(res);
10436 valuePush(ctxt, obj);
10437 ctxt->context->node = oldnode;
10438 CHECK_ERROR0;
10439 } else {
10440 /*
10441 * Initialize the new set.
10442 */
10443 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010444
Daniel Veillardf06307e2001-07-03 10:35:50 +000010445 for (i = 0; i < oldset->nodeNr; i++) {
10446 /*
10447 * Run the evaluation with a node list made of
10448 * a single item in the nodeset.
10449 */
10450 ctxt->context->node = oldset->nodeTab[i];
10451 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10452 valuePush(ctxt, tmp);
10453 ctxt->context->contextSize = oldset->nodeNr;
10454 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010455
Daniel Veillardf06307e2001-07-03 10:35:50 +000010456 if (op->ch2 != -1)
10457 total +=
10458 xmlXPathCompOpEval(ctxt,
10459 &comp->steps[op->ch2]);
10460 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010461
Daniel Veillardf06307e2001-07-03 10:35:50 +000010462 /*
10463 * The result of the evaluation need to be tested to
10464 * decided whether the filter succeeded or not
10465 */
10466 res = valuePop(ctxt);
10467 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10468 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10469 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010470
Daniel Veillardf06307e2001-07-03 10:35:50 +000010471 /*
10472 * Cleanup
10473 */
10474 if (res != NULL)
10475 xmlXPathFreeObject(res);
10476 if (ctxt->value == tmp) {
10477 res = valuePop(ctxt);
10478 xmlXPathFreeObject(res);
10479 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010480
Daniel Veillardf06307e2001-07-03 10:35:50 +000010481 ctxt->context->node = NULL;
10482 }
10483
10484 /*
10485 * The result is used as the new evaluation set.
10486 */
10487 xmlXPathFreeObject(obj);
10488 ctxt->context->node = NULL;
10489 ctxt->context->contextSize = -1;
10490 ctxt->context->proximityPosition = -1;
10491 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10492 }
10493 ctxt->context->node = oldnode;
10494 return (total);
10495 }
10496 case XPATH_OP_SORT:
10497 if (op->ch1 != -1)
10498 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010499 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010500 if ((ctxt->value != NULL) &&
10501 (ctxt->value->type == XPATH_NODESET) &&
10502 (ctxt->value->nodesetval != NULL))
10503 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10504 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010505#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010506 case XPATH_OP_RANGETO:{
10507 xmlXPathObjectPtr range;
10508 xmlXPathObjectPtr res, obj;
10509 xmlXPathObjectPtr tmp;
10510 xmlLocationSetPtr newset = NULL;
10511 xmlNodeSetPtr oldset;
10512 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010513
Daniel Veillardf06307e2001-07-03 10:35:50 +000010514 if (op->ch1 != -1)
10515 total +=
10516 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10517 if (op->ch2 == -1)
10518 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010519
Daniel Veillardf06307e2001-07-03 10:35:50 +000010520 CHECK_TYPE0(XPATH_NODESET);
10521 obj = valuePop(ctxt);
10522 oldset = obj->nodesetval;
10523 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010524
Daniel Veillardf06307e2001-07-03 10:35:50 +000010525 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010526
Daniel Veillardf06307e2001-07-03 10:35:50 +000010527 if (oldset != NULL) {
10528 for (i = 0; i < oldset->nodeNr; i++) {
10529 /*
10530 * Run the evaluation with a node list made of a single item
10531 * in the nodeset.
10532 */
10533 ctxt->context->node = oldset->nodeTab[i];
10534 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10535 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010536
Daniel Veillardf06307e2001-07-03 10:35:50 +000010537 if (op->ch2 != -1)
10538 total +=
10539 xmlXPathCompOpEval(ctxt,
10540 &comp->steps[op->ch2]);
10541 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010542
Daniel Veillardf06307e2001-07-03 10:35:50 +000010543 /*
10544 * The result of the evaluation need to be tested to
10545 * decided whether the filter succeeded or not
10546 */
10547 res = valuePop(ctxt);
10548 range =
10549 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10550 res);
10551 if (range != NULL) {
10552 xmlXPtrLocationSetAdd(newset, range);
10553 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010554
Daniel Veillardf06307e2001-07-03 10:35:50 +000010555 /*
10556 * Cleanup
10557 */
10558 if (res != NULL)
10559 xmlXPathFreeObject(res);
10560 if (ctxt->value == tmp) {
10561 res = valuePop(ctxt);
10562 xmlXPathFreeObject(res);
10563 }
10564
10565 ctxt->context->node = NULL;
10566 }
10567 }
10568
10569 /*
10570 * The result is used as the new evaluation set.
10571 */
10572 xmlXPathFreeObject(obj);
10573 ctxt->context->node = NULL;
10574 ctxt->context->contextSize = -1;
10575 ctxt->context->proximityPosition = -1;
10576 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
10577 return (total);
10578 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010579#endif /* LIBXML_XPTR_ENABLED */
10580 }
10581 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010582 "XPath: unknown precompiled operation %d\n", op->op);
10583 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010584}
10585
10586/**
10587 * xmlXPathRunEval:
10588 * @ctxt: the XPath parser context with the compiled expression
10589 *
10590 * Evaluate the Precompiled XPath expression in the given context.
10591 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010592static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010593xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10594 xmlXPathCompExprPtr comp;
10595
10596 if ((ctxt == NULL) || (ctxt->comp == NULL))
10597 return;
10598
10599 if (ctxt->valueTab == NULL) {
10600 /* Allocate the value stack */
10601 ctxt->valueTab = (xmlXPathObjectPtr *)
10602 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10603 if (ctxt->valueTab == NULL) {
10604 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010605 }
10606 ctxt->valueNr = 0;
10607 ctxt->valueMax = 10;
10608 ctxt->value = NULL;
10609 }
10610 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000010611 if(comp->last < 0) {
10612 xmlGenericError(xmlGenericErrorContext,
10613 "xmlXPathRunEval: last is less than zero\n");
10614 return;
10615 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010616 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10617}
10618
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010619/************************************************************************
10620 * *
10621 * Public interfaces *
10622 * *
10623 ************************************************************************/
10624
10625/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010626 * xmlXPathEvalPredicate:
10627 * @ctxt: the XPath context
10628 * @res: the Predicate Expression evaluation result
10629 *
10630 * Evaluate a predicate result for the current node.
10631 * A PredicateExpr is evaluated by evaluating the Expr and converting
10632 * the result to a boolean. If the result is a number, the result will
10633 * be converted to true if the number is equal to the position of the
10634 * context node in the context node list (as returned by the position
10635 * function) and will be converted to false otherwise; if the result
10636 * is not a number, then the result will be converted as if by a call
10637 * to the boolean function.
10638 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010639 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010640 */
10641int
10642xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
10643 if (res == NULL) return(0);
10644 switch (res->type) {
10645 case XPATH_BOOLEAN:
10646 return(res->boolval);
10647 case XPATH_NUMBER:
10648 return(res->floatval == ctxt->proximityPosition);
10649 case XPATH_NODESET:
10650 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010651 if (res->nodesetval == NULL)
10652 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010653 return(res->nodesetval->nodeNr != 0);
10654 case XPATH_STRING:
10655 return((res->stringval != NULL) &&
10656 (xmlStrlen(res->stringval) != 0));
10657 default:
10658 STRANGE
10659 }
10660 return(0);
10661}
10662
10663/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010664 * xmlXPathEvaluatePredicateResult:
10665 * @ctxt: the XPath Parser context
10666 * @res: the Predicate Expression evaluation result
10667 *
10668 * Evaluate a predicate result for the current node.
10669 * A PredicateExpr is evaluated by evaluating the Expr and converting
10670 * the result to a boolean. If the result is a number, the result will
10671 * be converted to true if the number is equal to the position of the
10672 * context node in the context node list (as returned by the position
10673 * function) and will be converted to false otherwise; if the result
10674 * is not a number, then the result will be converted as if by a call
10675 * to the boolean function.
10676 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010677 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010678 */
10679int
10680xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10681 xmlXPathObjectPtr res) {
10682 if (res == NULL) return(0);
10683 switch (res->type) {
10684 case XPATH_BOOLEAN:
10685 return(res->boolval);
10686 case XPATH_NUMBER:
10687 return(res->floatval == ctxt->context->proximityPosition);
10688 case XPATH_NODESET:
10689 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000010690 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000010691 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010692 return(res->nodesetval->nodeNr != 0);
10693 case XPATH_STRING:
10694 return((res->stringval != NULL) &&
10695 (xmlStrlen(res->stringval) != 0));
10696 default:
10697 STRANGE
10698 }
10699 return(0);
10700}
10701
10702/**
10703 * xmlXPathCompile:
10704 * @str: the XPath expression
10705 *
10706 * Compile an XPath expression
10707 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000010708 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010709 * the caller has to free the object.
10710 */
10711xmlXPathCompExprPtr
10712xmlXPathCompile(const xmlChar *str) {
10713 xmlXPathParserContextPtr ctxt;
10714 xmlXPathCompExprPtr comp;
10715
10716 xmlXPathInit();
10717
10718 ctxt = xmlXPathNewParserContext(str, NULL);
10719 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010720
Daniel Veillard40af6492001-04-22 08:50:55 +000010721 if (*ctxt->cur != 0) {
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010722 /*
10723 * aleksey: in some cases this line prints *second* error message
10724 * (see bug #78858) and probably this should be fixed.
10725 * However, we are not sure that all error messages are printed
10726 * out in other places. It's not critical so we leave it as-is for now
10727 */
Daniel Veillard40af6492001-04-22 08:50:55 +000010728 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10729 comp = NULL;
10730 } else {
10731 comp = ctxt->comp;
10732 ctxt->comp = NULL;
10733 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010734 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010735 if (comp != NULL) {
Daniel Veillardceb09b92002-10-04 11:46:37 +000010736 comp->expr = xmlStrdup(str);
10737#ifdef DEBUG_EVAL_COUNTS
Daniel Veillardf06307e2001-07-03 10:35:50 +000010738 comp->string = xmlStrdup(str);
10739 comp->nb = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010740#endif
Daniel Veillardceb09b92002-10-04 11:46:37 +000010741 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010742 return(comp);
10743}
10744
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010745/**
10746 * xmlXPathCompiledEval:
10747 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000010748 * @ctx: the XPath context
10749 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010750 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000010751 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010752 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000010753 * the caller has to free the object.
10754 */
10755xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010756xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000010757 xmlXPathParserContextPtr ctxt;
10758 xmlXPathObjectPtr res, tmp, init = NULL;
10759 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000010760#ifndef LIBXML_THREAD_ENABLED
10761 static int reentance = 0;
10762#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010763
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010764 if ((comp == NULL) || (ctx == NULL))
10765 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010766 xmlXPathInit();
10767
10768 CHECK_CONTEXT(ctx)
10769
Daniel Veillard81463942001-10-16 12:34:39 +000010770#ifndef LIBXML_THREAD_ENABLED
10771 reentance++;
10772 if (reentance > 1)
10773 xmlXPathDisableOptimizer = 1;
10774#endif
10775
Daniel Veillardf06307e2001-07-03 10:35:50 +000010776#ifdef DEBUG_EVAL_COUNTS
10777 comp->nb++;
10778 if ((comp->string != NULL) && (comp->nb > 100)) {
10779 fprintf(stderr, "100 x %s\n", comp->string);
10780 comp->nb = 0;
10781 }
10782#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010783 ctxt = xmlXPathCompParserContext(comp, ctx);
10784 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010785
10786 if (ctxt->value == NULL) {
10787 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010788 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000010789 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000010790 } else {
10791 res = valuePop(ctxt);
10792 }
10793
Daniel Veillardf06307e2001-07-03 10:35:50 +000010794
Owen Taylor3473f882001-02-23 17:55:21 +000010795 do {
10796 tmp = valuePop(ctxt);
10797 if (tmp != NULL) {
10798 if (tmp != init)
10799 stack++;
10800 xmlXPathFreeObject(tmp);
10801 }
10802 } while (tmp != NULL);
10803 if ((stack != 0) && (res != NULL)) {
10804 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010805 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000010806 stack);
10807 }
10808 if (ctxt->error != XPATH_EXPRESSION_OK) {
10809 xmlXPathFreeObject(res);
10810 res = NULL;
10811 }
10812
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010813
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010814 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010815 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000010816#ifndef LIBXML_THREAD_ENABLED
10817 reentance--;
10818#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010819 return(res);
10820}
10821
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010822/**
10823 * xmlXPathEvalExpr:
10824 * @ctxt: the XPath Parser context
10825 *
10826 * Parse and evaluate an XPath expression in the given context,
10827 * then push the result on the context stack
10828 */
10829void
10830xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
10831 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010832 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010833 xmlXPathRunEval(ctxt);
10834}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010835
10836/**
10837 * xmlXPathEval:
10838 * @str: the XPath expression
10839 * @ctx: the XPath context
10840 *
10841 * Evaluate the XPath Location Path in the given context.
10842 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010843 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010844 * the caller has to free the object.
10845 */
10846xmlXPathObjectPtr
10847xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
10848 xmlXPathParserContextPtr ctxt;
10849 xmlXPathObjectPtr res, tmp, init = NULL;
10850 int stack = 0;
10851
10852 xmlXPathInit();
10853
10854 CHECK_CONTEXT(ctx)
10855
10856 ctxt = xmlXPathNewParserContext(str, ctx);
10857 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010858
10859 if (ctxt->value == NULL) {
10860 xmlGenericError(xmlGenericErrorContext,
10861 "xmlXPathEval: evaluation failed\n");
10862 res = NULL;
10863 } else if (*ctxt->cur != 0) {
10864 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10865 res = NULL;
10866 } else {
10867 res = valuePop(ctxt);
10868 }
10869
10870 do {
10871 tmp = valuePop(ctxt);
10872 if (tmp != NULL) {
10873 if (tmp != init)
10874 stack++;
10875 xmlXPathFreeObject(tmp);
10876 }
10877 } while (tmp != NULL);
10878 if ((stack != 0) && (res != NULL)) {
10879 xmlGenericError(xmlGenericErrorContext,
10880 "xmlXPathEval: %d object left on the stack\n",
10881 stack);
10882 }
10883 if (ctxt->error != XPATH_EXPRESSION_OK) {
10884 xmlXPathFreeObject(res);
10885 res = NULL;
10886 }
10887
Owen Taylor3473f882001-02-23 17:55:21 +000010888 xmlXPathFreeParserContext(ctxt);
10889 return(res);
10890}
10891
10892/**
10893 * xmlXPathEvalExpression:
10894 * @str: the XPath expression
10895 * @ctxt: the XPath context
10896 *
10897 * Evaluate the XPath expression in the given context.
10898 *
10899 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
10900 * the caller has to free the object.
10901 */
10902xmlXPathObjectPtr
10903xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
10904 xmlXPathParserContextPtr pctxt;
10905 xmlXPathObjectPtr res, tmp;
10906 int stack = 0;
10907
10908 xmlXPathInit();
10909
10910 CHECK_CONTEXT(ctxt)
10911
10912 pctxt = xmlXPathNewParserContext(str, ctxt);
10913 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010914
10915 if (*pctxt->cur != 0) {
10916 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10917 res = NULL;
10918 } else {
10919 res = valuePop(pctxt);
10920 }
10921 do {
10922 tmp = valuePop(pctxt);
10923 if (tmp != NULL) {
10924 xmlXPathFreeObject(tmp);
10925 stack++;
10926 }
10927 } while (tmp != NULL);
10928 if ((stack != 0) && (res != NULL)) {
10929 xmlGenericError(xmlGenericErrorContext,
10930 "xmlXPathEvalExpression: %d object left on the stack\n",
10931 stack);
10932 }
10933 xmlXPathFreeParserContext(pctxt);
10934 return(res);
10935}
10936
Daniel Veillard42766c02002-08-22 20:52:17 +000010937/************************************************************************
10938 * *
10939 * Extra functions not pertaining to the XPath spec *
10940 * *
10941 ************************************************************************/
10942/**
10943 * xmlXPathEscapeUriFunction:
10944 * @ctxt: the XPath Parser context
10945 * @nargs: the number of arguments
10946 *
10947 * Implement the escape-uri() XPath function
10948 * string escape-uri(string $str, bool $escape-reserved)
10949 *
10950 * This function applies the URI escaping rules defined in section 2 of [RFC
10951 * 2396] to the string supplied as $uri-part, which typically represents all
10952 * or part of a URI. The effect of the function is to replace any special
10953 * character in the string by an escape sequence of the form %xx%yy...,
10954 * where xxyy... is the hexadecimal representation of the octets used to
10955 * represent the character in UTF-8.
10956 *
10957 * The set of characters that are escaped depends on the setting of the
10958 * boolean argument $escape-reserved.
10959 *
10960 * If $escape-reserved is true, all characters are escaped other than lower
10961 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
10962 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
10963 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
10964 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
10965 * A-F).
10966 *
10967 * If $escape-reserved is false, the behavior differs in that characters
10968 * referred to in [RFC 2396] as reserved characters are not escaped. These
10969 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
10970 *
10971 * [RFC 2396] does not define whether escaped URIs should use lower case or
10972 * upper case for hexadecimal digits. To ensure that escaped URIs can be
10973 * compared using string comparison functions, this function must always use
10974 * the upper-case letters A-F.
10975 *
10976 * Generally, $escape-reserved should be set to true when escaping a string
10977 * that is to form a single part of a URI, and to false when escaping an
10978 * entire URI or URI reference.
10979 *
10980 * In the case of non-ascii characters, the string is encoded according to
10981 * utf-8 and then converted according to RFC 2396.
10982 *
10983 * Examples
10984 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
10985 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
10986 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
10987 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
10988 *
10989 */
Daniel Veillard118aed72002-09-24 14:13:13 +000010990static void
Daniel Veillard42766c02002-08-22 20:52:17 +000010991xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
10992 xmlXPathObjectPtr str;
10993 int escape_reserved;
10994 xmlBufferPtr target;
10995 xmlChar *cptr;
10996 xmlChar escape[4];
10997
10998 CHECK_ARITY(2);
10999
11000 escape_reserved = xmlXPathPopBoolean(ctxt);
11001
11002 CAST_TO_STRING;
11003 str = valuePop(ctxt);
11004
11005 target = xmlBufferCreate();
11006
11007 escape[0] = '%';
11008 escape[3] = 0;
11009
11010 if (target) {
11011 for (cptr = str->stringval; *cptr; cptr++) {
11012 if ((*cptr >= 'A' && *cptr <= 'Z') ||
11013 (*cptr >= 'a' && *cptr <= 'z') ||
11014 (*cptr >= '0' && *cptr <= '9') ||
11015 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
11016 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
11017 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
11018 (*cptr == '%' &&
11019 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
11020 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
11021 (cptr[1] >= '0' && cptr[1] <= '9')) &&
11022 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
11023 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
11024 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
11025 (!escape_reserved &&
11026 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
11027 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
11028 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
11029 *cptr == ','))) {
11030 xmlBufferAdd(target, cptr, 1);
11031 } else {
11032 if ((*cptr >> 4) < 10)
11033 escape[1] = '0' + (*cptr >> 4);
11034 else
11035 escape[1] = 'A' - 10 + (*cptr >> 4);
11036 if ((*cptr & 0xF) < 10)
11037 escape[2] = '0' + (*cptr & 0xF);
11038 else
11039 escape[2] = 'A' - 10 + (*cptr & 0xF);
11040
11041 xmlBufferAdd(target, &escape[0], 3);
11042 }
11043 }
11044 }
11045 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
11046 xmlBufferFree(target);
11047 xmlXPathFreeObject(str);
11048}
11049
Owen Taylor3473f882001-02-23 17:55:21 +000011050/**
11051 * xmlXPathRegisterAllFunctions:
11052 * @ctxt: the XPath context
11053 *
11054 * Registers all default XPath functions in this context
11055 */
11056void
11057xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
11058{
11059 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
11060 xmlXPathBooleanFunction);
11061 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
11062 xmlXPathCeilingFunction);
11063 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
11064 xmlXPathCountFunction);
11065 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
11066 xmlXPathConcatFunction);
11067 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
11068 xmlXPathContainsFunction);
11069 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
11070 xmlXPathIdFunction);
11071 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
11072 xmlXPathFalseFunction);
11073 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
11074 xmlXPathFloorFunction);
11075 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
11076 xmlXPathLastFunction);
11077 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
11078 xmlXPathLangFunction);
11079 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
11080 xmlXPathLocalNameFunction);
11081 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
11082 xmlXPathNotFunction);
11083 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
11084 xmlXPathNameFunction);
11085 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
11086 xmlXPathNamespaceURIFunction);
11087 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
11088 xmlXPathNormalizeFunction);
11089 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
11090 xmlXPathNumberFunction);
11091 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
11092 xmlXPathPositionFunction);
11093 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
11094 xmlXPathRoundFunction);
11095 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
11096 xmlXPathStringFunction);
11097 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
11098 xmlXPathStringLengthFunction);
11099 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
11100 xmlXPathStartsWithFunction);
11101 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
11102 xmlXPathSubstringFunction);
11103 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
11104 xmlXPathSubstringBeforeFunction);
11105 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
11106 xmlXPathSubstringAfterFunction);
11107 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
11108 xmlXPathSumFunction);
11109 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
11110 xmlXPathTrueFunction);
11111 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
11112 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000011113
11114 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
11115 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
11116 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000011117}
11118
11119#endif /* LIBXML_XPATH_ENABLED */